409 lines
14 KiB
PHTML
409 lines
14 KiB
PHTML
<?php
|
|
|
|
/**
|
|
* @var int $activeUserCount
|
|
* @var int $inactiveUserCount
|
|
* @var int $activeTenantCount
|
|
* @var int $inactiveTenantCount
|
|
* @var int $activeDepartmentCount
|
|
* @var int $inactiveDepartmentCount
|
|
* @var int $activeRoleCount
|
|
* @var int $inactiveRoleCount
|
|
* @var int $rolesWithoutPermissionsCount
|
|
* @var int $permissionsWithoutRolesCount
|
|
* @var int $usersWithoutRolesCount
|
|
* @var int $usersWithoutTenantsCount
|
|
* @var int $departmentsWithoutTenantsCount
|
|
* @var int $mailLogSentCount
|
|
* @var int $mailLogFailedCount
|
|
* @var string $mailLogLastSentAt
|
|
* @var array $mailLogRecentFailed
|
|
*/
|
|
|
|
?>
|
|
<?php
|
|
$breadcrumbs = [
|
|
['label' => t('Home'), 'path' => 'admin'],
|
|
['label' => t('Statistics')],
|
|
];
|
|
require templatePath('partials/app-breadcrumb.phtml');
|
|
?>
|
|
<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="users" data-tab-default class="transparent tab-button">
|
|
<?php e(t('Users')); ?>
|
|
</button>
|
|
<button data-tab="tenants" class="transparent tab-button">
|
|
<?php e(t('Tenants')); ?>
|
|
</button>
|
|
<button data-tab="departments" class="transparent tab-button">
|
|
<?php e(t('Departments')); ?>
|
|
</button>
|
|
<button data-tab="roles-permissions" class="transparent tab-button">
|
|
<?php e(t('Roles & permissions')); ?>
|
|
</button>
|
|
<button data-tab="security" class="transparent tab-button">
|
|
<?php e(t('Security')); ?>
|
|
</button>
|
|
<?php if (can('mail_log.view')): ?>
|
|
<button data-tab="email-security" class="transparent tab-button">
|
|
<?php e(t('Email security')); ?>
|
|
</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Tab Panel: Users -->
|
|
<div data-tab-panel="users">
|
|
<div class="app-tiles">
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/users?active=active',
|
|
'label' => t('Active users'),
|
|
'count' => (string) $activeUserCount,
|
|
'icon' => 'bi bi-person-check-fill',
|
|
'iconBg' => '#d9f2e6',
|
|
'iconColor' => '#1f6a3a',
|
|
'tooltip' => t('Active users'),
|
|
]);
|
|
?>
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/users?active=inactive',
|
|
'label' => t('Inactive users'),
|
|
'count' => (string) $inactiveUserCount,
|
|
'icon' => 'bi bi-person-x-fill',
|
|
'iconBg' => '#ffe9e9',
|
|
'iconColor' => '#a32e2e',
|
|
'tooltip' => t('Inactive users'),
|
|
]);
|
|
?>
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/users?login_status=never',
|
|
'label' => t('Never logged in'),
|
|
'count' => (string) $usersNeverLoggedCount,
|
|
'icon' => 'bi bi-person-slash',
|
|
'iconBg' => '#fff2d9',
|
|
'iconColor' => '#9a5a00',
|
|
'tooltip' => t('Never logged in'),
|
|
]);
|
|
?>
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/users?email_verified=unverified',
|
|
'label' => t('Email unverified'),
|
|
'count' => (string) $usersUnverifiedCount,
|
|
'icon' => 'bi bi-shield-exclamation',
|
|
'iconBg' => '#fff2d9',
|
|
'iconColor' => '#9a5a00',
|
|
'tooltip' => t('Email unverified'),
|
|
]);
|
|
?>
|
|
</div>
|
|
<?php $canViewUsers = can('users.view'); ?>
|
|
<div class="app-stats-table">
|
|
<div class="app-stats-table-header">
|
|
<small><?php e(t('Recent logins')); ?></small>
|
|
</div>
|
|
<?php if (!empty($recentLogins)): ?>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th><?php e(t('User')); ?></th>
|
|
<th><?php e(t('Email')); ?></th>
|
|
<th><?php e(t('Last login')); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($recentLogins as $row): ?>
|
|
<tr>
|
|
<td>
|
|
<?php $name = trim(($row['first_name'] ?? '') . ' ' . ($row['last_name'] ?? '')); ?>
|
|
<?php if ($canViewUsers && !empty($row['uuid'])): ?>
|
|
<a href="admin/users/edit/<?php e($row['uuid']); ?>"><?php e($name); ?></a>
|
|
<?php else: ?>
|
|
<?php e($name); ?>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td><?php e($row['email'] ?? ''); ?></td>
|
|
<td><?php e(dt($row['last_login_at'] ?? '')); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<?php else: ?>
|
|
<small class="muted"><?php e(t('No entries found')); ?></small>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="app-stats-table">
|
|
<div class="app-stats-table-header">
|
|
<small><?php e(t('Never logged in')); ?></small>
|
|
</div>
|
|
<?php if (!empty($neverLoggedUsers)): ?>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th><?php e(t('User')); ?></th>
|
|
<th><?php e(t('Email')); ?></th>
|
|
<th><?php e(t('Created')); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($neverLoggedUsers as $row): ?>
|
|
<tr>
|
|
<td>
|
|
<?php $name = trim(($row['first_name'] ?? '') . ' ' . ($row['last_name'] ?? '')); ?>
|
|
<?php if ($canViewUsers && !empty($row['uuid'])): ?>
|
|
<a href="admin/users/edit/<?php e($row['uuid']); ?>"><?php e($name); ?></a>
|
|
<?php else: ?>
|
|
<?php e($name); ?>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td><?php e($row['email'] ?? ''); ?></td>
|
|
<td><?php e(dt($row['created'] ?? '')); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<?php else: ?>
|
|
<small class="muted"><?php e(t('No entries found')); ?></small>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab Panel: Tenants -->
|
|
<div data-tab-panel="tenants">
|
|
<div class="app-tiles">
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/tenants',
|
|
'label' => t('Active tenants'),
|
|
'count' => (string) $activeTenantCount,
|
|
'icon' => 'bi bi-buildings',
|
|
'iconBg' => '#e9f0ff',
|
|
'iconColor' => '#264db3',
|
|
'tooltip' => t('Active tenants'),
|
|
]);
|
|
?>
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/tenants',
|
|
'label' => t('Inactive tenants'),
|
|
'count' => (string) $inactiveTenantCount,
|
|
'icon' => 'bi bi-building-x',
|
|
'iconBg' => '#ffe9e9',
|
|
'iconColor' => '#a32e2e',
|
|
'tooltip' => t('Inactive tenants'),
|
|
]);
|
|
?>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab Panel: Departments -->
|
|
<div data-tab-panel="departments">
|
|
<div class="app-tiles">
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/departments?active=active',
|
|
'label' => t('Active departments'),
|
|
'count' => (string) $activeDepartmentCount,
|
|
'icon' => 'bi bi-diagram-3-fill',
|
|
'iconBg' => '#fff2d9',
|
|
'iconColor' => '#9a5a00',
|
|
'tooltip' => t('Active departments'),
|
|
]);
|
|
?>
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/departments?active=inactive',
|
|
'label' => t('Inactive departments'),
|
|
'count' => (string) $inactiveDepartmentCount,
|
|
'icon' => 'bi bi-diagram-3',
|
|
'iconBg' => '#ffe9e9',
|
|
'iconColor' => '#a32e2e',
|
|
'tooltip' => t('Inactive departments'),
|
|
]);
|
|
?>
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/departments',
|
|
'label' => t('Departments without tenants'),
|
|
'count' => (string) $departmentsWithoutTenantsCount,
|
|
'icon' => 'bi bi-diagram-3',
|
|
'iconBg' => '#fff2d9',
|
|
'iconColor' => '#9a5a00',
|
|
'tooltip' => t('Departments without tenants'),
|
|
]);
|
|
?>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab Panel: Roles & permissions -->
|
|
<div data-tab-panel="roles-permissions">
|
|
<div class="app-tiles">
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/roles?active=active',
|
|
'label' => t('Active roles'),
|
|
'count' => (string) $activeRoleCount,
|
|
'icon' => 'bi bi-shield-check',
|
|
'iconBg' => '#d9f2e6',
|
|
'iconColor' => '#1f6a3a',
|
|
'tooltip' => t('Active roles'),
|
|
]);
|
|
?>
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/roles?active=inactive',
|
|
'label' => t('Inactive roles'),
|
|
'count' => (string) $inactiveRoleCount,
|
|
'icon' => 'bi bi-shield-x',
|
|
'iconBg' => '#ffe9e9',
|
|
'iconColor' => '#a32e2e',
|
|
'tooltip' => t('Inactive roles'),
|
|
]);
|
|
?>
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/roles',
|
|
'label' => t('Roles without permissions'),
|
|
'count' => (string) $rolesWithoutPermissionsCount,
|
|
'icon' => 'bi bi-shield-exclamation',
|
|
'iconBg' => '#fff2d9',
|
|
'iconColor' => '#9a5a00',
|
|
'tooltip' => t('Roles without permissions'),
|
|
]);
|
|
?>
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/permissions',
|
|
'label' => t('Permissions without roles'),
|
|
'count' => (string) $permissionsWithoutRolesCount,
|
|
'icon' => 'bi bi-key-fill',
|
|
'iconBg' => '#ffe9e9',
|
|
'iconColor' => '#a32e2e',
|
|
'tooltip' => t('Permissions without roles'),
|
|
]);
|
|
?>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab Panel: Security -->
|
|
<div data-tab-panel="security">
|
|
<div class="app-tiles">
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/users?active=inactive',
|
|
'label' => t('Inactive users'),
|
|
'count' => (string) $inactiveUserCount,
|
|
'icon' => 'bi bi-person-x-fill',
|
|
'iconBg' => '#ffe9e9',
|
|
'iconColor' => '#a32e2e',
|
|
'tooltip' => t('Inactive users'),
|
|
]);
|
|
?>
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/users',
|
|
'label' => t('Users without roles'),
|
|
'count' => (string) $usersWithoutRolesCount,
|
|
'icon' => 'bi bi-person-dash',
|
|
'iconBg' => '#fff2d9',
|
|
'iconColor' => '#9a5a00',
|
|
'tooltip' => t('Users without roles'),
|
|
]);
|
|
?>
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/users',
|
|
'label' => t('Users without tenants'),
|
|
'count' => (string) $usersWithoutTenantsCount,
|
|
'icon' => 'bi bi-person-slash',
|
|
'iconBg' => '#ffe9e9',
|
|
'iconColor' => '#a32e2e',
|
|
'tooltip' => t('Users without tenants'),
|
|
]);
|
|
?>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab Panel: Email security -->
|
|
<?php if (can('mail_log.view')): ?>
|
|
<div data-tab-panel="email-security">
|
|
<div class="app-tiles">
|
|
<?php
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/mail-log?status=failed',
|
|
'label' => t('Mail failures'),
|
|
'count' => (string) $mailLogFailedCount,
|
|
'icon' => 'bi bi-envelope-x-fill',
|
|
'iconBg' => '#ffe9e9',
|
|
'iconColor' => '#a32e2e',
|
|
'tooltip' => t('Mail failures'),
|
|
]);
|
|
?>
|
|
<?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',
|
|
'tooltip' => t('Sent emails'),
|
|
]);
|
|
?>
|
|
<?php
|
|
$lastSentLabel = $mailLogLastSentAt ? dt($mailLogLastSentAt) : t('Never');
|
|
MintyPHP\Support\Tile::render([
|
|
'href' => 'admin/mail-log?status=sent',
|
|
'label' => t('Last email sent'),
|
|
'count' => $lastSentLabel,
|
|
'icon' => 'bi bi-clock-history',
|
|
'iconBg' => '#e9f0ff',
|
|
'iconColor' => '#264db3',
|
|
'tooltip' => t('Last email sent'),
|
|
]);
|
|
?>
|
|
</div>
|
|
<?php if (!empty($mailLogRecentFailed)): ?>
|
|
<div class="app-stats-table">
|
|
<div class="app-stats-table-header">
|
|
<small><?php e(t('Mail failures')); ?></small>
|
|
</div>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th><?php e(t('Recipient')); ?></th>
|
|
<th><?php e(t('Subject')); ?></th>
|
|
<th><?php e(t('Error')); ?></th>
|
|
<th><?php e(t('Created')); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($mailLogRecentFailed as $row): ?>
|
|
<tr>
|
|
<td><?php e($row['to_email'] ?? ''); ?></td>
|
|
<td><?php e($row['subject'] ?? ''); ?></td>
|
|
<td><?php e($row['error_message'] ?? ''); ?></td>
|
|
<td><?php e(dt($row['created_at'] ?? '')); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|