// Main JavaScript functionality document.addEventListener('DOMContentLoaded', function() { // Initialize application initializeApp(); }); function initializeApp() { // Initialize tooltips initializeTooltips(); // Initialize popovers initializePopovers(); // Initialize form validation initializeFormValidation(); // Initialize CSRF token initializeCSRF(); // Initialize event listeners initializeEventListeners(); } function initializeTooltips() { const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); tooltipTriggerList.map(function(tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl); }); } function initializePopovers() { const popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')); popoverTriggerList.map(function(popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl); }); } function initializeFormValidation() { // Add Bootstrap form validation const forms = document.querySelectorAll('.needs-validation'); Array.prototype.slice.call(forms).forEach(function(form) { form.addEventListener('submit', function(event) { if (!form.checkValidity()) { event.preventDefault(); event.stopPropagation(); } form.classList.add('was-validated'); }, false); }); } function initializeCSRF() { // Get CSRF token from meta tag if present const csrfToken = document.querySelector('meta[name="csrf-token"]'); if (csrfToken) { // Set default CSRF token for all AJAX requests const token = csrfToken.getAttribute('content'); // For jQuery if present if (typeof $ !== 'undefined') { $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", token); } } }); } } } function initializeEventListeners() { // Global error handling for fetch requests window.addEventListener('unhandledrejection', function(event) { console.error('Unhandled promise rejection:', event.reason); showNotification('An error occurred while processing your request', 'error'); }); // Auto-hide alerts after 5 seconds setTimeout(function() { const alerts = document.querySelectorAll('.alert'); alerts.forEach(function(alert) { if (alert.classList.contains('alert-success') || alert.classList.contains('alert-info')) { const bsAlert = new bootstrap.Alert(alert); bsAlert.close(); } }); }, 5000); } // Utility functions function showNotification(message, type = 'info', duration = 5000) { const alertHTML = ` `; const container = document.querySelector('.container-fluid') || document.body; container.insertAdjacentHTML('afterbegin', alertHTML); // Get reference to the created alert const alert = container.querySelector('.alert'); // Auto-hide after duration if (duration > 0) { setTimeout(function() { if (alert && alert.parentElement) { const bsAlert = new bootstrap.Alert(alert); bsAlert.close(); } }, duration); } // Return reference to the alert element for manual control return alert; } function showLoading(element, text = 'Loading...') { const originalHTML = element.innerHTML; element.innerHTML = ` ${text} `; element.disabled = true; return function() { element.innerHTML = originalHTML; element.disabled = false; }; } function formatBytes(bytes, decimals = 2) { if (bytes === 0) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } function formatDate(dateString) { const date = new Date(dateString); return date.toLocaleDateString() + ' ' + date.toLocaleTimeString(); } function debounce(func, wait, immediate) { let timeout; return function executedFunction() { const context = this; const args = arguments; const later = function() { timeout = null; if (!immediate) func.apply(context, args); }; const callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; } // API helper functions async function apiRequest(url, options = {}) { const defaultOptions = { method: 'GET', headers: { 'Content-Type': 'application/json', }, }; const config = { ...defaultOptions, ...options }; try { const response = await fetch(url, config); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error('API request failed:', error); throw error; } } async function apiGet(url) { return apiRequest(url); } async function apiPost(url, data) { return apiRequest(url, { method: 'POST', body: JSON.stringify(data), }); } async function apiPut(url, data) { return apiRequest(url, { method: 'PUT', body: JSON.stringify(data), }); } async function apiDelete(url) { return apiRequest(url, { method: 'DELETE', }); } // Script execution helpers function executeScript(scriptId, parameters = {}, projectId = null) { const data = { parameters: parameters }; if (projectId) { data.project_id = projectId; } return apiPost(`/api/scripts/${scriptId}/execute`, data); } function stopScript(scriptId, processId) { return apiPost(`/api/scripts/${scriptId}/stop`, { process_id: processId }); } function getScriptStatus(processId, userId) { return apiGet(`/api/scripts/status?process_id=${processId}&user_id=${userId}`); } // Project management helpers function createProject(groupId, projectName, description = '') { return apiPost('/api/projects', { group_id: groupId, project_name: projectName, description: description }); } function deleteProject(projectId) { return apiDelete(`/api/projects/${projectId}`); } function getUserProjects(groupId = null) { const url = groupId ? `/api/projects?group_id=${groupId}` : '/api/projects'; return apiGet(url); } // Conda environment helpers function getCondaEnvironments() { return apiGet('/api/conda/environments'); } function refreshCondaEnvironments() { return apiPost('/api/conda/refresh'); } // User preference helpers function updateUserPreferences(preferences) { return apiPost('/api/user/preferences', preferences); } // Export functions for use in other scripts window.ScriptsManager = { showNotification, showLoading, formatBytes, formatDate, debounce, apiGet, apiPost, apiPut, apiDelete, executeScript, stopScript, getScriptStatus, createProject, deleteProject, getUserProjects, getCondaEnvironments, refreshCondaEnvironments, updateUserPreferences };