|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
|
const uploadForm = document.getElementById('uploadForm'); |
|
|
const filenamesTextarea = document.getElementById('filenames'); |
|
|
const uploadBtn = document.getElementById('uploadBtn'); |
|
|
const clearBtn = document.getElementById('clearBtn'); |
|
|
const clearResultsBtn = document.getElementById('clearResultsBtn'); |
|
|
const resultsSection = document.getElementById('resultsSection'); |
|
|
const resultsContent = document.getElementById('resultsContent'); |
|
|
const loadingSection = document.getElementById('loadingSection'); |
|
|
const configBadge = document.getElementById('configBadge'); |
|
|
const healthBadge = document.getElementById('healthBadge'); |
|
|
|
|
|
|
|
|
init(); |
|
|
|
|
|
async function init() { |
|
|
await checkConfiguration(); |
|
|
await checkHealth(); |
|
|
setupEventListeners(); |
|
|
setupKeyboardShortcuts(); |
|
|
} |
|
|
|
|
|
function setupEventListeners() { |
|
|
|
|
|
uploadForm.addEventListener('submit', handleUpload); |
|
|
|
|
|
|
|
|
clearBtn.addEventListener('click', clearForm); |
|
|
clearResultsBtn.addEventListener('click', clearResults); |
|
|
|
|
|
|
|
|
filenamesTextarea.addEventListener('input', autoResizeTextarea); |
|
|
|
|
|
|
|
|
filenamesTextarea.addEventListener('input', validateInput); |
|
|
} |
|
|
|
|
|
function setupKeyboardShortcuts() { |
|
|
document.addEventListener('keydown', function(e) { |
|
|
|
|
|
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { |
|
|
e.preventDefault(); |
|
|
if (!uploadBtn.disabled) { |
|
|
handleUpload(e); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (e.key === 'Escape') { |
|
|
clearResults(); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
async function handleUpload(e) { |
|
|
e.preventDefault(); |
|
|
|
|
|
const filenames = filenamesTextarea.value.trim(); |
|
|
if (!filenames) { |
|
|
showError('Please enter at least one filename'); |
|
|
return; |
|
|
} |
|
|
|
|
|
setLoading(true); |
|
|
clearResults(); |
|
|
|
|
|
try { |
|
|
const formData = new FormData(); |
|
|
formData.append('filenames', filenames); |
|
|
|
|
|
const response = await fetch('/upload', { |
|
|
method: 'POST', |
|
|
body: formData |
|
|
}); |
|
|
|
|
|
if (!response.ok) { |
|
|
const errorData = await response.json(); |
|
|
throw new Error(errorData.detail || `HTTP ${response.status}`); |
|
|
} |
|
|
|
|
|
const data = await response.json(); |
|
|
displayResults(data.results); |
|
|
|
|
|
} catch (error) { |
|
|
console.error('Upload error:', error); |
|
|
showError(`Upload failed: ${error.message}`); |
|
|
} finally { |
|
|
setLoading(false); |
|
|
} |
|
|
} |
|
|
|
|
|
function displayResults(results) { |
|
|
if (!results) { |
|
|
showError('No results received from server'); |
|
|
return; |
|
|
} |
|
|
|
|
|
resultsContent.innerHTML = ''; |
|
|
|
|
|
|
|
|
const lines = results.split('\n').filter(line => line.trim()); |
|
|
|
|
|
lines.forEach(line => { |
|
|
const resultDiv = document.createElement('div'); |
|
|
resultDiv.className = 'result-line'; |
|
|
|
|
|
|
|
|
if (line.includes('β
')) { |
|
|
resultDiv.classList.add('result-success'); |
|
|
} else if (line.includes('β')) { |
|
|
resultDiv.classList.add('result-error'); |
|
|
} else if (line.includes('β©')) { |
|
|
resultDiv.classList.add('result-info'); |
|
|
} else { |
|
|
resultDiv.classList.add('result-warning'); |
|
|
} |
|
|
|
|
|
resultDiv.textContent = line; |
|
|
resultsContent.appendChild(resultDiv); |
|
|
}); |
|
|
|
|
|
resultsSection.style.display = 'block'; |
|
|
resultsSection.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); |
|
|
} |
|
|
|
|
|
function showError(message) { |
|
|
resultsContent.innerHTML = ''; |
|
|
const errorDiv = document.createElement('div'); |
|
|
errorDiv.className = 'result-line result-error'; |
|
|
errorDiv.textContent = `β ${message}`; |
|
|
resultsContent.appendChild(errorDiv); |
|
|
resultsSection.style.display = 'block'; |
|
|
} |
|
|
|
|
|
function setLoading(isLoading) { |
|
|
if (isLoading) { |
|
|
loadingSection.style.display = 'block'; |
|
|
uploadBtn.disabled = true; |
|
|
uploadBtn.querySelector('.btn-text').textContent = 'Processing...'; |
|
|
} else { |
|
|
loadingSection.style.display = 'none'; |
|
|
uploadBtn.disabled = false; |
|
|
uploadBtn.querySelector('.btn-text').textContent = 'Start Upload'; |
|
|
} |
|
|
} |
|
|
|
|
|
function clearForm() { |
|
|
filenamesTextarea.value = ''; |
|
|
filenamesTextarea.style.height = 'auto'; |
|
|
validateInput(); |
|
|
filenamesTextarea.focus(); |
|
|
} |
|
|
|
|
|
function clearResults() { |
|
|
resultsSection.style.display = 'none'; |
|
|
resultsContent.innerHTML = ''; |
|
|
} |
|
|
|
|
|
function autoResizeTextarea() { |
|
|
filenamesTextarea.style.height = 'auto'; |
|
|
filenamesTextarea.style.height = filenamesTextarea.scrollHeight + 'px'; |
|
|
} |
|
|
|
|
|
function validateInput() { |
|
|
const value = filenamesTextarea.value.trim(); |
|
|
uploadBtn.disabled = !value; |
|
|
|
|
|
if (value) { |
|
|
uploadBtn.classList.remove('btn-disabled'); |
|
|
} else { |
|
|
uploadBtn.classList.add('btn-disabled'); |
|
|
} |
|
|
} |
|
|
|
|
|
async function checkConfiguration() { |
|
|
try { |
|
|
const response = await fetch('/config'); |
|
|
const config = await response.json(); |
|
|
|
|
|
const allConfigured = Object.values(config).every(status => status.includes('β
')); |
|
|
|
|
|
if (allConfigured) { |
|
|
configBadge.textContent = 'Ready'; |
|
|
configBadge.className = 'status-badge success'; |
|
|
} else { |
|
|
configBadge.textContent = 'Incomplete'; |
|
|
configBadge.className = 'status-badge warning'; |
|
|
} |
|
|
} catch (error) { |
|
|
console.error('Config check failed:', error); |
|
|
configBadge.textContent = 'Error'; |
|
|
configBadge.className = 'status-badge error'; |
|
|
} |
|
|
} |
|
|
|
|
|
async function checkHealth() { |
|
|
try { |
|
|
const response = await fetch('/health'); |
|
|
const health = await response.json(); |
|
|
|
|
|
if (health.status === 'healthy') { |
|
|
healthBadge.textContent = 'Healthy'; |
|
|
healthBadge.className = 'status-badge success'; |
|
|
} else { |
|
|
healthBadge.textContent = 'Issues'; |
|
|
healthBadge.className = 'status-badge warning'; |
|
|
} |
|
|
} catch (error) { |
|
|
console.error('Health check failed:', error); |
|
|
healthBadge.textContent = 'Error'; |
|
|
healthBadge.className = 'status-badge error'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
setInterval(() => { |
|
|
checkConfiguration(); |
|
|
checkHealth(); |
|
|
}, 30000); |
|
|
|
|
|
|
|
|
if (!localStorage.getItem('keyboardHintShown')) { |
|
|
setTimeout(() => { |
|
|
showKeyboardHint(); |
|
|
localStorage.setItem('keyboardHintShown', 'true'); |
|
|
}, 2000); |
|
|
} |
|
|
|
|
|
function showKeyboardHint() { |
|
|
const hint = document.createElement('div'); |
|
|
hint.className = 'keyboard-hint'; |
|
|
hint.innerHTML = 'π‘ Tip: Use Ctrl+Enter to upload, Esc to clear results'; |
|
|
document.body.appendChild(hint); |
|
|
|
|
|
setTimeout(() => hint.classList.add('show'), 100); |
|
|
setTimeout(() => { |
|
|
hint.classList.remove('show'); |
|
|
setTimeout(() => document.body.removeChild(hint), 300); |
|
|
}, 4000); |
|
|
} |
|
|
|
|
|
|
|
|
uploadBtn.addEventListener('mouseenter', function() { |
|
|
if (!this.disabled) { |
|
|
this.style.transform = 'translateY(-2px)'; |
|
|
} |
|
|
}); |
|
|
|
|
|
uploadBtn.addEventListener('mouseleave', function() { |
|
|
this.style.transform = 'translateY(0)'; |
|
|
}); |
|
|
|
|
|
|
|
|
validateInput(); |
|
|
}); |
|
|
|
|
|
|