let progressInterval = null; function startProgressPolling() { if (progressInterval) { clearInterval(progressInterval); } progressInterval = setInterval(async () => { try { const response = await fetch('/api/progress'); const data = await response.json(); if (data.active) { updateProgressUI(data.message, data.progress, data.total); } else { stopProgressPolling(); } } catch (error) { console.error('Progress polling error:', error); } }, 500); } function stopProgressPolling() { if (progressInterval) { clearInterval(progressInterval); progressInterval = null; } } function updateProgressUI(message, progress, total) { const progressSection = document.getElementById('progressSection'); const progressBar = progressSection.querySelector('.progress-bar'); const progressMessage = document.getElementById('progressMessage'); const progressPercentage = document.getElementById('progressPercentage'); const percentage = total > 0 ? Math.round((progress / total) * 100) : 0; progressBar.style.width = percentage + '%'; if (progressPercentage) { progressPercentage.textContent = percentage + '%'; } progressBar.setAttribute('aria-valuenow', percentage); if (progressMessage) { progressMessage.textContent = message; } } function showProgress() { const progressSection = document.getElementById('progressSection'); const progressBar = progressSection.querySelector('.progress-bar'); const progressMessage = document.getElementById('progressMessage'); const progressPercentage = document.getElementById('progressPercentage'); progressBar.style.width = '0%'; if (progressPercentage) { progressPercentage.textContent = '0%'; } if (progressMessage) { progressMessage.textContent = 'Initializing...'; } document.getElementById('resultSection').style.display = 'none'; progressSection.style.display = 'block'; document.getElementById('generateBtn').disabled = true; startProgressPolling(); } function hideProgress() { const progressSection = document.getElementById('progressSection'); progressSection.style.display = 'none'; document.getElementById('generateBtn').disabled = false; stopProgressPolling(); } function showResult(message, type = 'danger') { const resultSection = document.getElementById('resultSection'); const resultMessage = document.getElementById('resultMessage'); const alertDiv = resultSection.querySelector('.alert'); const iconMap = { 'success': 'check-circle', 'danger': 'exclamation-circle', 'warning': 'exclamation-triangle', 'info': 'info-circle' }; const icon = iconMap[type] || 'info-circle'; alertDiv.className = `alert alert-${type}`; resultMessage.innerHTML = `${message}`; resultSection.style.display = 'block'; if (type === 'success') { setTimeout(() => { resultSection.style.display = 'none'; }, 5000); } } document.addEventListener('DOMContentLoaded', function() { const form = document.getElementById('generateForm'); if (form) { form.addEventListener('submit', async function(e) { e.preventDefault(); const formData = getFormData(); if (!formData) { showResult('Please select at least one country to continue', 'warning'); return; } await downloadConfiguration(formData); }); } }); async function downloadConfiguration(formData) { showProgress(); try { const endpoint = formData.app_type === 'raw-cidr' ? '/api/generate/raw' : '/api/generate'; const response = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(formData) }); hideProgress(); if (response.ok) { const fromCache = response.headers.get('X-From-Cache') === 'true'; const generatedAt = response.headers.get('X-Generated-At'); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; const contentDisposition = response.headers.get('Content-Disposition'); let filename = 'geoblock_config.conf'; if (contentDisposition) { const filenameMatch = contentDisposition.match(/filename="?(.+)"?/); if (filenameMatch) { filename = filenameMatch[1]; } } a.download = filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); if (fromCache) { showResult(` Lightning fast! Downloaded from cache: ${filename}`, 'success'); } else { showResult(`Configuration downloaded successfully: ${filename}`, 'success'); } } else { const error = await response.json(); showResult(error.error || 'An error occurred during download', 'danger'); } } catch (error) { hideProgress(); showResult('Network error: ' + error.message, 'danger'); } } function getFormData() { const countries = Array.from(document.querySelectorAll('input[name="countries"]:checked')) .map(input => input.value); if (countries.length === 0) { return null; } const useCacheCheckbox = document.getElementById('useCache'); return { countries: countries, app_type: document.getElementById('appType').value, app_variant: document.getElementById('appVariant').value, aggregate: document.getElementById('aggregate').checked, use_cache: useCacheCheckbox ? useCacheCheckbox.checked : true }; }