web_UI working - needs more tweaking

This commit is contained in:
nahakubuilde
2025-06-07 11:57:21 +01:00
parent 7053b82d30
commit ce0f7e0ac9
38 changed files with 1257 additions and 2799 deletions

View File

@@ -0,0 +1,260 @@
/* Custom CSS for SMTP Management Frontend */
/* Enhanced dark theme tweaks */
.card {
border: 1px solid #404040;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.card-header {
border-bottom: 1px solid #404040;
}
.table-dark {
--bs-table-bg: #2d3748;
--bs-table-striped-bg: #374151;
}
/* Status badges */
.status-active {
background-color: #10b981 !important;
}
.status-inactive {
background-color: #ef4444 !important;
}
.status-pending {
background-color: #f59e0b !important;
}
/* Custom form styling */
.form-control:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 0.2rem rgba(59, 130, 246, 0.25);
}
.form-select:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 0.2rem rgba(59, 130, 246, 0.25);
}
/* Copy button styling */
.copy-btn {
position: relative;
overflow: hidden;
}
.copy-btn::after {
content: "Copied!";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #10b981;
color: white;
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
opacity: 0;
transition: opacity 0.3s ease;
}
.copy-btn.copied::after {
opacity: 1;
}
/* DNS record styling */
.dns-record {
background-color: #1f2937;
border: 1px solid #374151;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 14px;
padding: 12px;
margin: 8px 0;
}
.dns-record-header {
color: #9ca3af;
font-weight: bold;
margin-bottom: 4px;
}
.dns-record-value {
color: #e5e7eb;
word-break: break-all;
}
/* Log entry styling */
.log-entry {
border-left: 4px solid #374151;
padding-left: 12px;
margin-bottom: 8px;
}
.log-entry.log-error {
border-left-color: #ef4444;
}
.log-entry.log-warning {
border-left-color: #f59e0b;
}
.log-entry.log-info {
border-left-color: #3b82f6;
}
.log-entry.log-success {
border-left-color: #10b981;
}
/* Statistics cards */
.stat-card {
background: linear-gradient(135deg, #1f2937 0%, #374151 100%);
border: 1px solid #4b5563;
border-radius: 8px;
padding: 20px;
text-align: center;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.stat-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
}
.stat-number {
font-size: 2.5rem;
font-weight: bold;
color: #3b82f6;
}
.stat-label {
color: #9ca3af;
font-size: 0.9rem;
margin-top: 8px;
}
/* Loading states */
.loading {
opacity: 0.6;
pointer-events: none;
}
.spinner-border-sm {
width: 1rem;
height: 1rem;
}
/* Responsive table wrapper */
.table-responsive {
border-radius: 8px;
border: 1px solid #404040;
}
/* Alert styling */
.alert {
border: none;
border-radius: 8px;
}
.alert-success {
background-color: rgba(16, 185, 129, 0.1);
color: #10b981;
border-left: 4px solid #10b981;
}
.alert-danger {
background-color: rgba(239, 68, 68, 0.1);
color: #ef4444;
border-left: 4px solid #ef4444;
}
.alert-warning {
background-color: rgba(245, 158, 11, 0.1);
color: #f59e0b;
border-left: 4px solid #f59e0b;
}
.alert-info {
background-color: rgba(59, 130, 246, 0.1);
color: #3b82f6;
border-left: 4px solid #3b82f6;
}
/* Custom scrollbar */
.custom-scrollbar {
scrollbar-width: thin;
scrollbar-color: #4b5563 #1f2937;
}
.custom-scrollbar::-webkit-scrollbar {
width: 8px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: #1f2937;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background-color: #4b5563;
border-radius: 4px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background-color: #6b7280;
}
/* Animation classes */
.fade-in {
animation: fadeIn 0.3s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.slide-in {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from { transform: translateX(-20px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
/* Tooltip styling */
.tooltip {
font-size: 12px;
}
.tooltip-inner {
background-color: #1f2937;
border: 1px solid #374151;
}
.tooltip.bs-tooltip-top .tooltip-arrow::before {
border-top-color: #374151;
}
.tooltip.bs-tooltip-bottom .tooltip-arrow::before {
border-bottom-color: #374151;
}
/* Mobile responsiveness */
@media (max-width: 768px) {
.stat-number {
font-size: 1.8rem;
}
.dns-record {
font-size: 12px;
padding: 8px;
}
.table-responsive {
font-size: 14px;
}
}

View File

@@ -0,0 +1,285 @@
/* Custom JavaScript for SMTP Management Frontend */
// Global utilities
const SMTPManagement = {
// Copy text to clipboard
copyToClipboard: function(text, button) {
navigator.clipboard.writeText(text).then(() => {
this.showCopySuccess(button);
}).catch(err => {
console.error('Failed to copy: ', err);
this.showCopyError(button);
});
},
// Show copy success feedback
showCopySuccess: function(button) {
const originalText = button.innerHTML;
button.innerHTML = '<i class="fas fa-check me-1"></i>Copied!';
button.classList.remove('btn-outline-light');
button.classList.add('btn-success');
setTimeout(() => {
button.innerHTML = originalText;
button.classList.remove('btn-success');
button.classList.add('btn-outline-light');
}, 2000);
},
// Show copy error feedback
showCopyError: function(button) {
const originalText = button.innerHTML;
button.innerHTML = '<i class="fas fa-times me-1"></i>Failed!';
button.classList.remove('btn-outline-light');
button.classList.add('btn-danger');
setTimeout(() => {
button.innerHTML = originalText;
button.classList.remove('btn-danger');
button.classList.add('btn-outline-light');
}, 2000);
},
// Format timestamps
formatTimestamp: function(timestamp) {
const date = new Date(timestamp);
return date.toLocaleString();
},
// Validate email address
validateEmail: function(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email);
},
// Validate IP address
validateIP: function(ip) {
const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
return ipv4Regex.test(ip) || ipv6Regex.test(ip);
},
// Show loading state
showLoading: function(element) {
element.classList.add('loading');
const spinner = element.querySelector('.spinner-border');
if (spinner) {
spinner.style.display = 'inline-block';
}
},
// Hide loading state
hideLoading: function(element) {
element.classList.remove('loading');
const spinner = element.querySelector('.spinner-border');
if (spinner) {
spinner.style.display = 'none';
}
},
// Show toast notification
showToast: function(message, type = 'info') {
const toastContainer = document.getElementById('toast-container') || this.createToastContainer();
const toast = this.createToast(message, type);
toastContainer.appendChild(toast);
// Auto-remove after 5 seconds
setTimeout(() => {
toast.remove();
}, 5000);
},
// Create toast container
createToastContainer: function() {
const container = document.createElement('div');
container.id = 'toast-container';
container.className = 'position-fixed top-0 end-0 p-3';
container.style.zIndex = '1056';
document.body.appendChild(container);
return container;
},
// Create toast element
createToast: function(message, type) {
const toast = document.createElement('div');
toast.className = `toast align-items-center text-white bg-${type} border-0`;
toast.setAttribute('role', 'alert');
toast.innerHTML = `
<div class="d-flex">
<div class="toast-body">${message}</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
</div>
`;
// Initialize Bootstrap toast
const bsToast = new bootstrap.Toast(toast);
bsToast.show();
return toast;
},
// Auto-refresh functionality
autoRefresh: function(url, interval = 30000) {
setInterval(() => {
fetch(url, {
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.text())
.then(html => {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const newContent = doc.querySelector('#refresh-content');
const currentContent = document.querySelector('#refresh-content');
if (newContent && currentContent) {
currentContent.innerHTML = newContent.innerHTML;
}
})
.catch(error => {
console.error('Auto-refresh failed:', error);
});
}, interval);
}
};
// DNS verification functionality
const DNSVerification = {
// Check DNS record
checkDNSRecord: function(domain, recordType, expectedValue) {
return fetch('/email/check-dns', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify({
domain: domain,
record_type: recordType,
expected_value: expectedValue
})
})
.then(response => response.json());
},
// Update DNS status indicator
updateDNSStatus: function(element, status, message) {
const statusIcon = element.querySelector('.dns-status-icon');
const statusText = element.querySelector('.dns-status-text');
if (statusIcon && statusText) {
statusIcon.className = `dns-status-icon fas ${status === 'valid' ? 'fa-check-circle text-success' : 'fa-times-circle text-danger'}`;
statusText.textContent = message;
}
}
};
// Form validation
const FormValidation = {
// Real-time email validation
validateEmailField: function(input) {
const isValid = SMTPManagement.validateEmail(input.value);
this.updateFieldStatus(input, isValid, 'Please enter a valid email address');
return isValid;
},
// Real-time IP validation
validateIPField: function(input) {
const isValid = SMTPManagement.validateIP(input.value);
this.updateFieldStatus(input, isValid, 'Please enter a valid IP address');
return isValid;
},
// Update field validation status
updateFieldStatus: function(input, isValid, errorMessage) {
const feedback = input.parentNode.querySelector('.invalid-feedback');
if (isValid) {
input.classList.remove('is-invalid');
input.classList.add('is-valid');
if (feedback) feedback.textContent = '';
} else {
input.classList.remove('is-valid');
input.classList.add('is-invalid');
if (feedback) feedback.textContent = errorMessage;
}
}
};
// Initialize on DOM load
document.addEventListener('DOMContentLoaded', function() {
// Initialize tooltips
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(function(tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// Initialize form validation
const emailInputs = document.querySelectorAll('input[type="email"]');
emailInputs.forEach(input => {
input.addEventListener('blur', () => FormValidation.validateEmailField(input));
});
const ipInputs = document.querySelectorAll('input[data-validate="ip"]');
ipInputs.forEach(input => {
input.addEventListener('blur', () => FormValidation.validateIPField(input));
});
// Initialize auto-refresh for logs page
if (document.querySelector('#logs-page')) {
SMTPManagement.autoRefresh(window.location.href, 30000);
}
// Initialize current IP detection
const currentIPSpan = document.querySelector('#current-ip');
if (currentIPSpan) {
fetch('https://api.ipify.org?format=json')
.then(response => response.json())
.then(data => {
currentIPSpan.textContent = data.ip;
})
.catch(() => {
currentIPSpan.textContent = 'Unable to detect';
});
}
// Initialize copy buttons
const copyButtons = document.querySelectorAll('.copy-btn');
copyButtons.forEach(button => {
button.addEventListener('click', function() {
const textToCopy = this.getAttribute('data-copy') || this.nextElementSibling.textContent;
SMTPManagement.copyToClipboard(textToCopy, this);
});
});
// Initialize DNS check buttons
const dnsCheckButtons = document.querySelectorAll('.dns-check-btn');
dnsCheckButtons.forEach(button => {
button.addEventListener('click', function() {
const domain = this.getAttribute('data-domain');
const recordType = this.getAttribute('data-record-type');
const expectedValue = this.getAttribute('data-expected-value');
const statusElement = this.closest('.dns-record').querySelector('.dns-status');
SMTPManagement.showLoading(this);
DNSVerification.checkDNSRecord(domain, recordType, expectedValue)
.then(result => {
DNSVerification.updateDNSStatus(statusElement, result.status, result.message);
SMTPManagement.hideLoading(this);
})
.catch(error => {
console.error('DNS check failed:', error);
DNSVerification.updateDNSStatus(statusElement, 'error', 'DNS check failed');
SMTPManagement.hideLoading(this);
});
});
});
});
// Export for use in other scripts
window.SMTPManagement = SMTPManagement;
window.DNSVerification = DNSVerification;
window.FormValidation = FormValidation;