DKIM key management front end - ok
This commit is contained in:
@@ -156,22 +156,24 @@
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Flash messages -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ 'danger' if category == 'error' else category }} alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-{{ 'exclamation-triangle' if category == 'error' else 'check-circle' if category == 'success' else 'info-circle' }} me-2"></i>
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
<!-- Toast container for notifications -->
|
||||
<div class="toast-container position-fixed top-0 end-0 p-3" style="z-index: 1090;">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="toast align-items-center text-bg-{{ 'danger' if category == 'error' else category }} border-0" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="true" data-bs-delay="5000">
|
||||
<div class="d-flex">
|
||||
<div class="toast-body">
|
||||
<i class="bi bi-{{ 'exclamation-triangle' if category == 'error' else 'check-circle' if category == 'success' else 'info-circle' }} me-2"></i>
|
||||
{{ message }}
|
||||
</div>
|
||||
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
<!-- Page content -->
|
||||
<main>
|
||||
@@ -180,6 +182,28 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Custom Confirmation Modal -->
|
||||
<div class="modal fade" id="confirmationModal" tabindex="-1" aria-labelledby="confirmationModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="confirmationModalLabel">
|
||||
<i class="bi bi-question-circle me-2"></i>
|
||||
Confirm Action
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="confirmationModalBody">
|
||||
Are you sure you want to proceed?
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="confirmationModalConfirm">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
@@ -197,22 +221,113 @@
|
||||
setInterval(updateTime, 1000);
|
||||
updateTime(); // Initial call
|
||||
|
||||
// Auto-dismiss alerts after 5 seconds
|
||||
setTimeout(function() {
|
||||
const alerts = document.querySelectorAll('.alert:not(.alert-permanent)');
|
||||
alerts.forEach(function(alert) {
|
||||
const bootstrapAlert = new bootstrap.Alert(alert);
|
||||
bootstrapAlert.close();
|
||||
// Initialize toasts
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const toastElements = document.querySelectorAll('.toast');
|
||||
toastElements.forEach(function(toastElement) {
|
||||
const toast = new bootstrap.Toast(toastElement);
|
||||
toast.show();
|
||||
});
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
// Confirmation dialogs for delete actions
|
||||
// Function to show dynamic toasts
|
||||
function showToast(message, type = 'info') {
|
||||
const toastContainer = document.querySelector('.toast-container');
|
||||
const toastId = 'toast-' + Date.now();
|
||||
const iconMap = {
|
||||
'danger': 'exclamation-triangle',
|
||||
'success': 'check-circle',
|
||||
'warning': 'exclamation-triangle',
|
||||
'info': 'info-circle'
|
||||
};
|
||||
|
||||
const toastHtml = `
|
||||
<div id="${toastId}" class="toast align-items-center text-bg-${type} border-0" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="true" data-bs-delay="5000">
|
||||
<div class="d-flex">
|
||||
<div class="toast-body">
|
||||
<i class="bi bi-${iconMap[type] || 'info-circle'} me-2"></i>
|
||||
${message}
|
||||
</div>
|
||||
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
toastContainer.insertAdjacentHTML('beforeend', toastHtml);
|
||||
const newToast = new bootstrap.Toast(document.getElementById(toastId));
|
||||
newToast.show();
|
||||
|
||||
// Remove toast element after it's hidden
|
||||
document.getElementById(toastId).addEventListener('hidden.bs.toast', function() {
|
||||
this.remove();
|
||||
});
|
||||
}
|
||||
|
||||
// Custom confirmation dialog to replace browser alerts
|
||||
function showConfirmation(message, title = 'Confirm Action', confirmButtonText = 'Confirm', confirmButtonClass = 'btn-primary') {
|
||||
return new Promise((resolve) => {
|
||||
const modal = document.getElementById('confirmationModal');
|
||||
const modalTitle = document.getElementById('confirmationModalLabel');
|
||||
const modalBody = document.getElementById('confirmationModalBody');
|
||||
const confirmButton = document.getElementById('confirmationModalConfirm');
|
||||
|
||||
// Set content
|
||||
modalTitle.innerHTML = `<i class="bi bi-question-circle me-2"></i>${title}`;
|
||||
modalBody.textContent = message;
|
||||
confirmButton.textContent = confirmButtonText;
|
||||
|
||||
// Reset button classes and add new one
|
||||
confirmButton.className = `btn ${confirmButtonClass}`;
|
||||
|
||||
// Set up event handlers
|
||||
const handleConfirm = () => {
|
||||
resolve(true);
|
||||
bootstrap.Modal.getInstance(modal).hide();
|
||||
cleanup();
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
resolve(false);
|
||||
cleanup();
|
||||
};
|
||||
|
||||
const cleanup = () => {
|
||||
confirmButton.removeEventListener('click', handleConfirm);
|
||||
modal.removeEventListener('hidden.bs.modal', handleCancel);
|
||||
};
|
||||
|
||||
confirmButton.addEventListener('click', handleConfirm);
|
||||
modal.addEventListener('hidden.bs.modal', handleCancel, { once: true });
|
||||
|
||||
// Show modal
|
||||
new bootstrap.Modal(modal).show();
|
||||
});
|
||||
}
|
||||
|
||||
// Confirmation dialogs for delete actions with data-confirm attribute
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const deleteButtons = document.querySelectorAll('[data-confirm]');
|
||||
deleteButtons.forEach(function(button) {
|
||||
button.addEventListener('click', function(e) {
|
||||
if (!confirm(this.getAttribute('data-confirm'))) {
|
||||
e.preventDefault();
|
||||
button.addEventListener('click', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const confirmMessage = this.getAttribute('data-confirm');
|
||||
const confirmed = await showConfirmation(
|
||||
confirmMessage,
|
||||
'Confirm Action',
|
||||
'Confirm',
|
||||
'btn-danger'
|
||||
);
|
||||
|
||||
if (confirmed) {
|
||||
// If it's a form button, submit the form
|
||||
const form = this.closest('form');
|
||||
if (form) {
|
||||
form.submit();
|
||||
} else if (this.href) {
|
||||
// If it's a link, navigate to the URL
|
||||
window.location.href = this.href;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user