296 lines
8.1 KiB
JavaScript
296 lines
8.1 KiB
JavaScript
// 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 = `
|
|
<div class="alert alert-${type} alert-dismissible fade show" role="alert">
|
|
${message}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
`;
|
|
|
|
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 = `
|
|
<span class="spinner-border spinner-border-sm me-2" role="status"></span>
|
|
${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
|
|
}; |