> $ssoTenantRows * @var array> $usersMicrosoftOnlyRows * @var array> $usersMicrosoftSyncGapRows * @var bool $customFieldStatsAvailable * @var int $customFieldsSelectionWithoutOptionsCount * @var int $customFieldTenantsWithSelectionWithoutOptionsCount * @var int $customFieldsInactiveWithValuesCount * @var int $customFieldsUnusedActiveCount * @var string $customFieldsSelectionWithoutOptionsHref * @var string $customFieldTenantsWithSelectionWithoutOptionsHref * @var string $customFieldsInactiveWithValuesHref * @var string $customFieldsUnusedActiveHref * @var array> $customFieldIssueTenantRows * @var bool $apiStatsAvailable * @var int $apiRequests24hCount * @var int $apiRequestsPrev24hCount * @var float $apiRequestTrendPercent * @var int $apiErrors4xx24hCount * @var int $apiErrors5xx24hCount * @var int $apiP95DurationMs * @var int $apiTokensExpiring7dCount * @var array> $apiTopErrorRows * @var array> $apiSlowEndpointRows * @var bool $importStatsAvailable * @var int $importRuns7dCount * @var int $importRunsPrev7dCount * @var float $importRunTrendPercent * @var int $importRowsCreated7dCount * @var int $importRowsFailed7dCount * @var int $importPartialOrFailedRuns7dCount * @var float $importSuccessRate7dPercent * @var int $importAverageDurationMs7d * @var array> $importRecentRunRows * @var array> $importProfileRows * @var array> $importTopErrorCodeRows * @var bool $auditStatsAvailable * @var bool $systemAuditStatsAvailable * @var bool $userLifecycleAuditStatsAvailable * @var int $systemAuditEvents24hCount * @var int $systemAuditFailed24hCount * @var int $systemAuditDenied24hCount * @var int $systemAuditEventsPrev24hCount * @var float $systemAuditTrendPercent * @var array> $systemAuditTopEventTypeRows * @var array> $systemAuditRecentRiskRows * @var string $systemAuditAll24hHref * @var string $systemAuditFailed24hHref * @var string $systemAuditDenied24hHref * @var int $lifecycleRuns7dCount * @var int $lifecycleRunsPrev7dCount * @var float $lifecycleRunTrendPercent * @var int $lifecycleFailed7dCount * @var int $lifecycleSkipped7dCount * @var int $lifecycleRestore7dCount * @var array> $lifecycleTopReasonRows * @var array> $lifecycleRecentRiskRows * @var string $lifecycleAll7dHref * @var string $lifecycleFailed7dHref * @var string $lifecycleRestore7dHref * @var bool $scheduledStatsAvailable * @var int $scheduledEnabledJobsCount * @var int $scheduledOverdueJobsCount * @var int $scheduledRuns24hCount * @var int $scheduledFailedRuns24hCount * @var bool $schedulerRunnerIsActive * @var string $schedulerRunnerLastHeartbeatAt * @var string $schedulerRunnerLastResult * @var string $schedulerRunnerLastErrorCode * @var int $usersNeverLoggedCount * @var int $usersUnverifiedCount * @var int $mailLogSentCount * @var int $mailLogFailedCount * @var string $mailLogLastSentAt * @var array $mailLogRecentFailed */ $pageAuth = is_array($viewAuth['page'] ?? null) ? $viewAuth['page'] : []; $canViewMailLog = (bool) ($pageAuth['can_view_mail_log'] ?? false); $canViewUsers = (bool) ($pageAuth['can_view_users'] ?? false); $canViewTenants = (bool) ($pageAuth['can_view_tenants'] ?? false); $canViewImportAudit = false; $canViewSystemAudit = false; $canViewUserLifecycleAudit = false; $canViewAuditTab = (bool) ($auditStatsAvailable ?? false) && ( ($canViewSystemAudit && (bool) ($systemAuditStatsAvailable ?? false)) || ($canViewUserLifecycleAudit && (bool) ($userLifecycleAuditStatsAvailable ?? false)) ); ?>


'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'), ]); ?> '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'), ]); ?> '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'), ]); ?> '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'), ]); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
'admin/tenants', 'label' => t('Active tenants'), 'count' => (string) $activeTenantCount, 'icon' => 'bi bi-buildings', 'iconBg' => '#e9f0ff', 'iconColor' => '#264db3', 'tooltip' => t('Active tenants'), ]); ?> 'admin/tenants', 'label' => t('Inactive tenants'), 'count' => (string) $inactiveTenantCount, 'icon' => 'bi bi-building-x', 'iconBg' => '#ffe9e9', 'iconColor' => '#a32e2e', 'tooltip' => t('Inactive tenants'), ]); ?>
'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'), ]); ?> 'admin/departments?active=inactive', 'label' => t('Inactive departments'), 'count' => (string) $inactiveDepartmentCount, 'icon' => 'bi bi-diagram-3', 'iconBg' => '#ffe9e9', 'iconColor' => '#a32e2e', 'tooltip' => t('Inactive departments'), ]); ?>
'admin/roles?active=active', 'label' => t('Active roles'), 'count' => (string) $activeRoleCount, 'icon' => 'bi bi-shield-check', 'iconBg' => '#d9f2e6', 'iconColor' => '#1f6a3a', 'tooltip' => t('Active roles'), ]); ?> 'admin/roles?active=inactive', 'label' => t('Inactive roles'), 'count' => (string) $inactiveRoleCount, 'icon' => 'bi bi-shield-x', 'iconBg' => '#ffe9e9', 'iconColor' => '#a32e2e', 'tooltip' => t('Inactive roles'), ]); ?> 'admin/roles', 'label' => t('Roles without permissions'), 'count' => (string) $rolesWithoutPermissionsCount, 'icon' => 'bi bi-shield-exclamation', 'iconBg' => '#fff2d9', 'iconColor' => '#9a5a00', 'tooltip' => t('Roles without permissions'), ]); ?> 'admin/permissions', 'label' => t('Permissions without roles'), 'count' => (string) $permissionsWithoutRolesCount, 'icon' => 'bi bi-key-fill', 'iconBg' => '#ffe9e9', 'iconColor' => '#a32e2e', 'tooltip' => t('Permissions without roles'), ]); ?>
'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'), ]); ?> 'admin/users', 'label' => t('Users without roles'), 'count' => (string) $usersWithoutRolesCount, 'icon' => 'bi bi-person-dash', 'iconBg' => '#fff2d9', 'iconColor' => '#9a5a00', 'tooltip' => t('Users without roles'), ]); ?> 'admin/users', 'label' => t('Users without tenants'), 'count' => (string) $usersWithoutTenantsCount, 'icon' => 'bi bi-person-slash', 'iconBg' => '#ffe9e9', 'iconColor' => '#a32e2e', 'tooltip' => t('Users without tenants'), ]); ?>
$systemAuditAll24hHref, 'label' => t('System audit events (24h)'), 'count' => (string) $systemAuditEvents24hCount, 'icon' => 'bi bi-journal-text', 'iconBg' => '#e9f0ff', 'iconColor' => '#264db3', 'tooltip' => t('System audit events (24h)'), ]); ?> $systemAuditFailed24hHref, 'label' => t('System audit risks (24h)'), 'count' => (string) $systemAuditRisk24hCount, 'icon' => 'bi bi-exclamation-triangle-fill', 'iconBg' => '#fff2d9', 'iconColor' => '#9a5a00', 'tooltip' => t('System audit risks (24h)'), ]); ?> $lifecycleAll7dHref, 'label' => t('Lifecycle runs (7d)'), 'count' => (string) $lifecycleRuns7dCount, 'icon' => 'bi bi-person-gear', 'iconBg' => '#e9f0ff', 'iconColor' => '#264db3', 'tooltip' => t('Lifecycle runs (7d)'), ]); ?> $lifecycleFailed7dHref, 'label' => t('Lifecycle risks (7d)'), 'count' => (string) $lifecycleRisk7dCount, 'icon' => 'bi bi-exclamation-octagon-fill', 'iconBg' => '#ffe9e9', 'iconColor' => '#a32e2e', 'tooltip' => t('Lifecycle risks (7d)'), ]); ?> $lifecycleRestore7dHref, 'label' => t('Restore actions (7d)'), 'count' => (string) $lifecycleRestore7dCount, 'icon' => 'bi bi-arrow-counterclockwise', 'iconBg' => '#d9f2e6', 'iconColor' => '#1f6a3a', 'tooltip' => t('Restore actions (7d)'), ]); ?>
0): ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
0): ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
'admin/tenants', 'label' => t('SSO-enabled tenants'), 'count' => (string) $ssoEnabledTenantCount, 'icon' => 'bi bi-microsoft', 'iconBg' => '#e9f0ff', 'iconColor' => '#264db3', 'tooltip' => t('SSO-enabled tenants'), ]); ?> 'admin/tenants', 'label' => t('SSO-enforced tenants'), 'count' => (string) $ssoEnforcedTenantCount, 'icon' => 'bi bi-shield-lock-fill', 'iconBg' => '#d9f2e6', 'iconColor' => '#1f6a3a', 'tooltip' => t('SSO-enforced tenants'), ]); ?> 'admin/tenants', 'label' => t('SSO rollout'), 'count' => number_format($ssoEnabledTenantPercent, 1, '.', '') . '%', 'icon' => 'bi bi-speedometer2', 'iconBg' => '#fff2d9', 'iconColor' => '#9a5a00', 'tooltip' => t('SSO rollout'), ]); ?> 'admin/users', 'label' => t('Users with Microsoft-only login'), 'count' => (string) $usersMicrosoftOnlyCount, 'icon' => 'bi bi-person-lock', 'iconBg' => '#f2f2f2', 'iconColor' => '#555555', 'tooltip' => t('Users with Microsoft-only login'), ]); ?> 'admin/users', 'label' => t('Microsoft profile sync gaps'), 'count' => (string) $usersMicrosoftSyncGapsCount, 'icon' => 'bi bi-person-exclamation', 'iconBg' => '#ffe9e9', 'iconColor' => '#a32e2e', 'tooltip' => t('Microsoft profile sync gaps'), ]); ?>
$customFieldsSelectionWithoutOptionsHref, 'label' => t('Selection fields without options'), 'count' => (string) $customFieldsSelectionWithoutOptionsCount, 'icon' => 'bi bi-list-check', 'iconBg' => '#fff2d9', 'iconColor' => '#9a5a00', 'tooltip' => t('Selection fields without options'), ]); ?> $customFieldTenantsWithSelectionWithoutOptionsHref, 'label' => t('Tenants with broken selection fields'), 'count' => (string) $customFieldTenantsWithSelectionWithoutOptionsCount, 'icon' => 'bi bi-exclamation-triangle', 'iconBg' => '#ffe9e9', 'iconColor' => '#a32e2e', 'tooltip' => t('Tenants with broken selection fields'), ]); ?> $customFieldsInactiveWithValuesHref, 'label' => t('Inactive custom fields with values'), 'count' => (string) $customFieldsInactiveWithValuesCount, 'icon' => 'bi bi-archive-fill', 'iconBg' => '#e9f0ff', 'iconColor' => '#264db3', 'tooltip' => t('Inactive custom fields with values'), ]); ?> $customFieldsUnusedActiveHref, 'label' => t('Unused active custom fields'), 'count' => (string) $customFieldsUnusedActiveCount, 'icon' => 'bi bi-slash-circle', 'iconBg' => '#f2f2f2', 'iconColor' => '#555555', 'tooltip' => t('Unused active custom fields'), ]); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
'admin/api-audit', 'label' => t('API requests (24h)'), 'count' => (string) $apiRequests24hCount, 'icon' => 'bi bi-bar-chart-line-fill', 'iconBg' => '#e9f0ff', 'iconColor' => '#264db3', 'tooltip' => t('API requests (24h)'), ]); ?> 0 ? (($apiRequestTrendPercent > 0 ? '+' : '') . number_format($apiRequestTrendPercent, 1, '.', '') . '%') : 'n/a'; appTile([ 'href' => 'admin/api-audit', 'label' => t('Request trend vs previous 24h'), 'count' => $trendLabel, 'icon' => 'bi bi-graph-up-arrow', 'iconBg' => '#f2f2f2', 'iconColor' => '#555555', 'tooltip' => t('Request trend vs previous 24h'), ]); ?> 'admin/api-audit', 'label' => t('4xx errors (24h)'), 'count' => (string) $apiErrors4xx24hCount, 'icon' => 'bi bi-shield-exclamation', 'iconBg' => '#fff2d9', 'iconColor' => '#9a5a00', 'tooltip' => t('4xx errors (24h)'), ]); ?> 'admin/api-audit', 'label' => t('5xx errors (24h)'), 'count' => (string) $apiErrors5xx24hCount, 'icon' => 'bi bi-bug-fill', 'iconBg' => '#ffe9e9', 'iconColor' => '#a32e2e', 'tooltip' => t('5xx errors (24h)'), ]); ?> 'admin/api-audit', 'label' => t('P95 response time (ms)'), 'count' => (string) $apiP95DurationMs, 'icon' => 'bi bi-stopwatch-fill', 'iconBg' => '#d9f2e6', 'iconColor' => '#1f6a3a', 'tooltip' => t('P95 response time (ms)'), ]); ?> 'admin/settings?tab=api', 'label' => t('Tokens expiring in 7 days'), 'count' => (string) $apiTokensExpiring7dCount, 'icon' => 'bi bi-key-fill', 'iconBg' => '#fff2d9', 'iconColor' => '#9a5a00', 'tooltip' => t('Tokens expiring in 7 days'), ]); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
'admin/import-audit', 'label' => t('Import runs (7d)'), 'count' => (string) $importRuns7dCount, 'icon' => 'bi bi-box-arrow-in-down', 'iconBg' => '#e9f0ff', 'iconColor' => '#264db3', 'tooltip' => t('Import runs (7d)'), ]); ?> 'admin/import-audit', 'label' => t('Created rows (7d)'), 'count' => (string) $importRowsCreated7dCount, 'icon' => 'bi bi-person-plus-fill', 'iconBg' => '#d9f2e6', 'iconColor' => '#1f6a3a', 'tooltip' => t('Created rows (7d)'), ]); ?> 'admin/import-audit', 'label' => t('Failed rows (7d)'), 'count' => (string) $importRowsFailed7dCount, 'icon' => 'bi bi-exclamation-octagon-fill', 'iconBg' => '#ffe9e9', 'iconColor' => '#a32e2e', 'tooltip' => t('Failed rows (7d)'), ]); ?> 0 ? number_format($importSuccessRate7dPercent, 1, '.', '') . '%' : 'n/a'; appTile([ 'href' => 'admin/import-audit', 'label' => t('Success rate (7d)'), 'count' => $importSuccessLabel, 'icon' => 'bi bi-check2-circle', 'iconBg' => '#d9f2e6', 'iconColor' => '#1f6a3a', 'tooltip' => t('Success rate (7d)'), ]); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
t('No entries found'), 'size' => 'compact']; require templatePath('partials/app-empty-state.phtml'); ?>
'admin/scheduled-jobs', 'label' => t('Enabled jobs'), 'count' => (string) $scheduledEnabledJobsCount, 'icon' => 'bi bi-check2-square', 'iconBg' => '#d9f2e6', 'iconColor' => '#1f6a3a', 'tooltip' => t('Enabled jobs'), ]); ?> 'admin/scheduled-jobs', 'label' => t('Overdue jobs'), 'count' => (string) $scheduledOverdueJobsCount, 'icon' => 'bi bi-exclamation-triangle-fill', 'iconBg' => '#fff2d9', 'iconColor' => '#9a5a00', 'tooltip' => t('Overdue jobs'), ]); ?> 'admin/scheduled-jobs', 'label' => t('Scheduler runs (24h)'), 'count' => (string) $scheduledRuns24hCount, 'icon' => 'bi bi-clock-history', 'iconBg' => '#e9f0ff', 'iconColor' => '#264db3', 'tooltip' => t('Scheduler runs (24h)'), ]); ?> 'admin/scheduled-jobs', 'label' => t('Failed scheduler runs (24h)'), 'count' => (string) $scheduledFailedRuns24hCount, 'icon' => 'bi bi-x-octagon-fill', 'iconBg' => '#ffe9e9', 'iconColor' => '#a32e2e', 'tooltip' => t('Failed scheduler runs (24h)'), ]); ?> 'admin/scheduled-jobs', 'label' => t('Cron runner active'), 'count' => $runnerStatusLabel, 'icon' => $schedulerRunnerIsActive ? 'bi bi-heart-pulse-fill' : 'bi bi-heartbreak-fill', 'iconBg' => $schedulerRunnerIsActive ? '#d9f2e6' : '#ffe9e9', 'iconColor' => $schedulerRunnerIsActive ? '#1f6a3a' : '#a32e2e', 'tooltip' => $runnerTooltip !== '' ? $runnerTooltip : t('Cron runner active'), ]); ?>
'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'), ]); ?> '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'), ]); ?> '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'), ]); ?>