Switch PHP views to Twig and add 2FA/UI enhancements

Migrate many view templates from raw PHP to Twig and modernize UI/UX for 2FA and settings. Controllers updated to provide avatar data and two-factor info (ProfileController, UserController) and SettingsController now includes timezone lists, notification preset selection, cron path, cached update state and rollback availability. ErrorHandler now attempts to render error pages via a new Core\TwigService with a safe fallback to raw PHP views. TwoFactorService generation silences deprecated warnings during QR code creation. Numerous .php view files were removed and replaced with .twig equivalents (2fa setup/verify/backup-codes and many auth, dashboard, domains, errors, layout, users, tags, tld-registry, etc.), and core/TwigService was added. These changes move the app toward a Twig-based templating system, improve 2FA flows, surface avatar images in lists/profiles, and make error rendering more robust.
This commit is contained in:
Hosteroid
2026-03-03 18:21:32 +02:00
parent cd4e3e6bcc
commit 4818172bc6
73 changed files with 9948 additions and 10686 deletions

176
app/Views/errors/500.twig Normal file
View File

@@ -0,0 +1,176 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>500 - Internal Server Error</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: {
DEFAULT: '#4A90E2',
dark: '#357ABD',
}
}
}
}
}
</script>
</head>
<body class="bg-gradient-to-br from-red-50 to-orange-100 min-h-screen flex items-center justify-center p-6">
<div class="max-w-2xl w-full">
<div class="bg-white rounded-2xl shadow-2xl p-12 text-center">
<div class="mb-8">
<i class="fas fa-exclamation-circle text-red-500 text-8xl mb-4"></i>
</div>
<h1 class="text-9xl font-bold text-gray-800 mb-4">500</h1>
<h2 class="text-3xl font-bold text-gray-700 mb-4">Internal Server Error</h2>
<p class="text-gray-600 text-lg mb-8 leading-relaxed">
Oops! Something went wrong on our end. We're working to fix the issue.
</p>
{% if error_id is defined and error_id %}
<div class="bg-blue-50 border border-blue-200 rounded-lg p-5 mb-8">
<div class="flex items-center justify-center space-x-3">
<div class="flex-shrink-0">
<i class="fas fa-fingerprint text-blue-600 text-2xl"></i>
</div>
<div class="text-left">
<p class="text-sm font-medium text-gray-700 mb-1">Error Reference ID:</p>
<div class="flex items-center space-x-2">
<code class="text-lg font-mono font-bold text-primary bg-white px-3 py-1 rounded border border-blue-200">
{{ error_id }}
</code>
<button onclick="copyErrorId()"
class="px-3 py-1 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors"
title="Copy Error ID">
<i class="fas fa-copy"></i>
</button>
</div>
<p class="text-xs text-gray-600 mt-2">
<i class="fas fa-info-circle mr-1"></i>
Please include this ID when reporting the issue
</p>
</div>
</div>
</div>
{% endif %}
<div class="flex flex-col sm:flex-row gap-4 justify-center">
<a href="/" class="inline-flex items-center justify-center px-8 py-4 bg-primary text-white rounded-lg hover:bg-primary-dark transition-all duration-200 shadow-lg hover:shadow-xl transform hover:-translate-y-0.5">
<i class="fas fa-home mr-2"></i>
Go to Dashboard
</a>
<button onclick="history.back()" class="inline-flex items-center justify-center px-8 py-4 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-all duration-200 shadow-md hover:shadow-lg">
<i class="fas fa-arrow-left mr-2"></i>
Go Back
</button>
<button onclick="location.reload()" class="inline-flex items-center justify-center px-8 py-4 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-all duration-200 shadow-md hover:shadow-lg">
<i class="fas fa-redo mr-2"></i>
Try Again
</button>
</div>
<div class="mt-12 pt-8 border-t border-gray-200">
<p class="text-sm text-gray-500 mb-4">Quick Links:</p>
<div class="flex flex-wrap justify-center gap-4">
<a href="/domains" class="text-primary hover:text-primary-dark transition-colors duration-150">
<i class="fas fa-globe mr-1"></i>
Domains
</a>
<a href="/groups" class="text-primary hover:text-primary-dark transition-colors duration-150">
<i class="fas fa-bell mr-1"></i>
Notification Groups
</a>
<a href="/debug/whois" class="text-primary hover:text-primary-dark transition-colors duration-150">
<i class="fas fa-search mr-1"></i>
WHOIS Lookup
</a>
{% if auth is defined and auth.isAdmin|default(false) %}
<a href="/settings" class="text-primary hover:text-primary-dark transition-colors duration-150">
<i class="fas fa-cog mr-1"></i>
Settings
</a>
{% endif %}
</div>
</div>
<div class="mt-8 bg-gray-50 rounded-lg p-4">
<p class="text-sm text-gray-600">
<i class="fas fa-life-ring text-primary mr-1"></i>
If this problem persists, please contact your system administrator
{% if error_id is defined and error_id %}
and provide the error reference ID above.
{% else %}
.
{% endif %}
</p>
</div>
</div>
<div class="text-center mt-8">
<p class="text-gray-600">
<i class="fas fa-globe text-primary"></i>
<span class="ml-2">Domain Monitor &copy; {{ "now"|date("Y") }}</span>
</p>
</div>
</div>
<script>
function copyErrorId() {
const errorId = {{ (error_id|default(''))|json_encode|raw }};
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(errorId).then(() => {
showSuccess();
}).catch(() => {
fallbackCopy(errorId);
});
} else {
fallbackCopy(errorId);
}
}
function fallbackCopy(text) {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand('copy');
showSuccess();
} catch (err) {
console.error('Copy failed:', err);
}
document.body.removeChild(textArea);
}
function showSuccess() {
const btn = event.target.closest('button');
if (btn) {
const originalHTML = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-check"></i>';
btn.classList.add('bg-green-600', 'hover:bg-green-700');
btn.classList.remove('bg-blue-600', 'hover:bg-blue-700');
setTimeout(() => {
btn.innerHTML = originalHTML;
btn.classList.remove('bg-green-600', 'hover:bg-green-700');
btn.classList.add('bg-blue-600', 'hover:bg-blue-700');
}, 2000);
}
}
</script>
</body>
</html>