2025-05-24 15:47:40 +02:00

349 lines
12 KiB
JavaScript

// UI utilities and common functions
// Page navigation
function showPage(pageId) {
try {
console.log('=== showPage called with pageId:', pageId, '===');
// Hide all pages
const pages = document.querySelectorAll('.page');
console.log('Found pages:', pages.length);
pages.forEach((page, index) => {
console.log(`Page ${index}: ${page.id}, currently visible: ${page.style.display !== 'none'}`);
page.style.display = 'none';
});
// Show the selected page
const targetPageId = pageId + 'Page';
const targetPage = document.getElementById(targetPageId);
console.log('Looking for page with ID:', targetPageId);
console.log('Target page element:', targetPage);
if (targetPage) {
console.log('Setting target page display to block');
targetPage.style.display = 'block';
console.log('Target page is now visible:', targetPage.style.display === 'block');
// Update URL hash only if it's different to avoid loops
const currentHash = window.location.hash.substring(1);
if (currentHash !== pageId) {
console.log('Updating URL hash from', currentHash, 'to:', pageId);
window.location.hash = pageId;
} else {
console.log('Hash already correct, not updating');
}
// Update navigation active state
updateNavActiveState(pageId);
// Update app state
if (window.SeReactApp) {
window.SeReactApp.currentPage = pageId;
}
// Load page data if needed
console.log('About to load page data for:', pageId);
loadPageData(pageId);
console.log('=== showPage completed for:', pageId, '===');
} else {
console.error('Target page not found:', targetPageId);
console.log('Available page IDs:', Array.from(document.querySelectorAll('.page')).map(p => p.id));
}
} catch (error) {
console.error('Error in showPage:', error);
showAlert('Error loading page: ' + error.message, 'danger');
}
}
// Update navigation active state
function updateNavActiveState(activePageId) {
const navLinks = document.querySelectorAll('.navbar-nav .nav-link');
navLinks.forEach(link => {
link.classList.remove('active');
const onclick = link.getAttribute('onclick');
if (onclick && onclick.includes(`'${activePageId}'`)) {
link.classList.add('active');
}
});
}
// Load page-specific data
function loadPageData(pageId) {
console.log('=== loadPageData called with pageId:', pageId, '===');
try {
switch (pageId) {
case 'config':
console.log('Loading config page - about to call initializeConfigForm');
// Add a small delay to ensure the page is visible before initializing the form
setTimeout(() => {
console.log('Timeout fired, calling initializeConfigForm now');
initializeConfigForm();
}, 100);
break;
case 'images':
console.log('Loading images page');
loadImages();
break;
case 'teams':
console.log('Loading teams page');
loadTeams();
break;
case 'users':
console.log('Loading users page');
loadUsers();
break;
case 'apiKeys':
console.log('Loading apiKeys page');
loadApiKeys();
break;
case 'search':
console.log('Loading search page');
initializeSearchForm();
break;
default:
console.log('No specific loader for page:', pageId);
}
console.log('=== loadPageData completed for:', pageId, '===');
} catch (error) {
console.error('Error in loadPageData:', error);
}
}
// Alert system
function showAlert(message, type = 'info', persistent = false) {
const alertContainer = document.getElementById('alertContainer');
const alertId = 'alert-' + Date.now();
const alertHtml = `
<div id="${alertId}" class="alert alert-${type} alert-dismissible fade show" role="alert">
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
alertContainer.insertAdjacentHTML('beforeend', alertHtml);
// Auto-dismiss non-persistent alerts
if (!persistent) {
setTimeout(() => {
const alertElement = document.getElementById(alertId);
if (alertElement) {
const bsAlert = new bootstrap.Alert(alertElement);
bsAlert.close();
}
}, 5000);
}
}
// Clear all alerts
function clearAlerts() {
const alertContainer = document.getElementById('alertContainer');
alertContainer.innerHTML = '';
}
// Modal utilities
function createModal(id, title, body, footer = '') {
const modalHtml = `
<div class="modal fade" id="${id}" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">${title}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
${body}
</div>
${footer ? `<div class="modal-footer">${footer}</div>` : ''}
</div>
</div>
</div>
`;
const modalContainer = document.getElementById('modalContainer');
modalContainer.insertAdjacentHTML('beforeend', modalHtml);
return new bootstrap.Modal(document.getElementById(id));
}
// Remove modal from DOM
function removeModal(id) {
const modal = document.getElementById(id);
if (modal) {
modal.remove();
}
}
// Loading state utilities
function setLoadingState(element, loading = true) {
if (loading) {
element.disabled = true;
element.dataset.originalText = element.innerHTML;
element.innerHTML = '<span class="loading-spinner"></span> Loading...';
} else {
element.disabled = false;
element.innerHTML = element.dataset.originalText || element.innerHTML;
}
}
// Format date for display
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
}
// Format file size
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// Truncate text
function truncateText(text, maxLength = 100) {
if (text.length <= maxLength) return text;
return text.substring(0, maxLength) + '...';
}
// Escape HTML
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Debounce function
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Confirm dialog
function confirmAction(message, callback) {
if (confirm(message)) {
callback();
}
}
// Copy to clipboard
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
showAlert('Copied to clipboard!', 'success');
} catch (err) {
console.error('Failed to copy: ', err);
showAlert('Failed to copy to clipboard', 'danger');
}
}
// Initialize tooltips
function initializeTooltips() {
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
}
// Initialize popovers
function initializePopovers() {
const popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
popoverTriggerList.map(function (popoverTriggerEl) {
return new bootstrap.Popover(popoverTriggerEl);
});
}
// Handle file drag and drop
function setupFileDropZone(element, callback) {
element.addEventListener('dragover', (e) => {
e.preventDefault();
element.classList.add('dragover');
});
element.addEventListener('dragleave', (e) => {
e.preventDefault();
element.classList.remove('dragover');
});
element.addEventListener('drop', (e) => {
e.preventDefault();
element.classList.remove('dragover');
const files = Array.from(e.dataTransfer.files);
callback(files);
});
}
// Validate file type and size
function validateFile(file, allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], maxSize = 10 * 1024 * 1024) {
if (!allowedTypes.includes(file.type)) {
throw new Error(`File type ${file.type} is not allowed. Allowed types: ${allowedTypes.join(', ')}`);
}
if (file.size > maxSize) {
throw new Error(`File size ${formatFileSize(file.size)} exceeds maximum allowed size of ${formatFileSize(maxSize)}`);
}
return true;
}
// Create image preview
function createImagePreview(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => resolve(e.target.result);
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
// Initialize UI components (called from app.js)
function initializeUI() {
console.log('UI initialization called from app.js');
// Initialize tooltips and popovers
initializeTooltips();
initializePopovers();
// Update navigation state
updateNavigationState();
// Show initial page
const hash = window.location.hash.substring(1);
const initialPage = hash || 'home';
console.log('Initial page:', initialPage);
// Set initial app state
if (window.SeReactApp) {
window.SeReactApp.currentPage = initialPage;
}
showPage(initialPage);
}
// Test function for debugging
function testPageNavigation() {
console.log('Testing page navigation...');
console.log('Available pages:', document.querySelectorAll('.page').length);
const pages = ['home', 'config', 'teams', 'users'];
pages.forEach(pageId => {
const pageElement = document.getElementById(pageId + 'Page');
console.log(`Page ${pageId}:`, pageElement ? 'Found' : 'NOT FOUND');
});
// Test showing teams page
console.log('Testing showPage("teams")...');
showPage('teams');
}
// Make test function available globally
window.testPageNavigation = testPageNavigation;