| document.addEventListener('DOMContentLoaded', () => { |
| |
| const elements = { |
| badgeDifficulty: document.getElementById('badge-difficulty'), |
| badgeStep: document.getElementById('badge-step'), |
| taskDescription: document.getElementById('task-description'), |
| codeSnippet: document.getElementById('code-snippet'), |
| langBadge: document.getElementById('lang-badge'), |
| feedbackContainer: document.getElementById('feedback-container'), |
| previousFeedback: document.getElementById('previous-feedback'), |
| |
| form: document.getElementById('action-form'), |
| submitBtn: document.getElementById('btn-submit-action'), |
| resetBtn: document.getElementById('btn-reset-env'), |
| |
| toast: document.getElementById('reward-toast'), |
| toastTitle: document.getElementById('toast-title'), |
| toastMessage: document.getElementById('toast-message'), |
| toastClose: document.getElementById('toast-close'), |
|
|
| |
| inputBugIdentified: document.getElementById('input-bug-identified'), |
| inputBugType: document.getElementById('input-bug-type'), |
| inputSeverity: document.getElementById('input-severity'), |
| inputBugLocation: document.getElementById('input-bug-location'), |
| inputBugDescription: document.getElementById('input-bug-description'), |
| inputSuggestedFix: document.getElementById('input-suggested-fix'), |
| |
| |
| tabs: document.querySelectorAll('.mac-tab'), |
| panes: document.querySelectorAll('.tab-pane'), |
| |
| |
| themeToggle: document.getElementById('theme-toggle'), |
| html: document.documentElement, |
| sunIcon: document.getElementById('sun-icon'), |
| moonIcon: document.getElementById('moon-icon') |
| }; |
|
|
| let isDone = false; |
|
|
| |
| function setTheme(theme) { |
| elements.html.setAttribute('data-theme', theme); |
| localStorage.setItem('theme', theme); |
| |
| if (theme === 'dark') { |
| elements.sunIcon.classList.add('hidden'); |
| elements.moonIcon.classList.remove('hidden'); |
| } else { |
| elements.sunIcon.classList.remove('hidden'); |
| elements.moonIcon.classList.add('hidden'); |
| } |
| } |
|
|
| |
| const savedTheme = localStorage.getItem('theme') || 'dark'; |
| setTheme(savedTheme); |
|
|
| elements.themeToggle.addEventListener('click', () => { |
| const currentTheme = elements.html.getAttribute('data-theme'); |
| setTheme(currentTheme === 'dark' ? 'light' : 'dark'); |
| }); |
|
|
| |
| elements.tabs.forEach(tab => { |
| tab.addEventListener('click', () => { |
| const target = tab.getAttribute('data-tab'); |
| |
| |
| elements.tabs.forEach(t => t.classList.remove('active')); |
| tab.classList.add('active'); |
| |
| |
| elements.panes.forEach(pane => { |
| if (pane.id === `tab-${target}`) { |
| pane.classList.add('active'); |
| } else { |
| pane.classList.remove('active'); |
| } |
| }); |
| }); |
| }); |
|
|
| |
| async function resetEnvironment(difficulty = 'easy') { |
| elements.submitBtn.disabled = true; |
| elements.resetBtn.disabled = true; |
| isDone = false; |
| |
| try { |
| const res = await fetch(`/reset?difficulty=${difficulty}`, { method: 'POST' }); |
| if (!res.ok) throw new Error('Failed to reset environment'); |
| const data = await res.json(); |
| updateObservation(data.observation); |
| |
| |
| elements.form.reset(); |
| document.getElementById('observation-section').classList.remove('environment-done'); |
| hideToast(); |
| } catch (e) { |
| showToast('Error', e.message, true); |
| } finally { |
| elements.submitBtn.disabled = false; |
| elements.resetBtn.disabled = false; |
| } |
| } |
|
|
| function updateObservation(obs) { |
| elements.badgeDifficulty.textContent = obs.difficulty.toUpperCase(); |
| elements.badgeStep.textContent = `Step ${obs.step_number}/${obs.max_steps}`; |
| elements.taskDescription.textContent = obs.task_description; |
| elements.langBadge.textContent = `Language: ${obs.language}`; |
| |
| |
| elements.codeSnippet.textContent = obs.code_snippet; |
| elements.codeSnippet.className = `language-${obs.language}`; |
| hljs.highlightElement(elements.codeSnippet); |
|
|
| if (obs.previous_feedback) { |
| elements.previousFeedback.textContent = obs.previous_feedback; |
| elements.feedbackContainer.classList.remove('hidden'); |
| } else { |
| elements.feedbackContainer.classList.add('hidden'); |
| } |
| |
| if (obs.step_number >= obs.max_steps) { |
| isDone = true; |
| } |
| } |
|
|
| |
| elements.form.addEventListener('submit', async (e) => { |
| e.preventDefault(); |
| if (isDone) { |
| showToast('Environment Finished', 'Please reset to start a new episode.', true); |
| return; |
| } |
|
|
| const action = { |
| bug_identified: elements.inputBugIdentified.value === 'true', |
| bug_location: elements.inputBugLocation.value, |
| bug_type: elements.inputBugType.value, |
| bug_description: elements.inputBugDescription.value, |
| severity: elements.inputSeverity.value, |
| suggested_fix: elements.inputSuggestedFix.value |
| }; |
|
|
| elements.submitBtn.disabled = true; |
| elements.submitBtn.textContent = "Submitting..."; |
|
|
| try { |
| const res = await fetch('/step', { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify(action) |
| }); |
| |
| if (!res.ok) { |
| const err = await res.json(); |
| throw new Error(err.detail || 'Failed to submit action'); |
| } |
|
|
| const data = await res.json(); |
| updateObservation(data.observation); |
| |
| if (data.done) { |
| isDone = true; |
| const totalScore = data.info?.total_score || data.reward; |
| showToast('Episode Completed!', `Final Score: ${totalScore.toFixed(2)}`, false); |
| document.getElementById('observation-section').classList.add('environment-done'); |
| } else { |
| showToast('Step Evaluated', `Step Reward: ${data.reward.toFixed(2)}`, false); |
| } |
| } catch (e) { |
| showToast('Action Failed', e.message, true); |
| } finally { |
| elements.submitBtn.disabled = false; |
| elements.submitBtn.textContent = "Submit Action"; |
| } |
| }); |
|
|
| |
| elements.resetBtn.addEventListener('click', () => { |
| const randomDifficulty = ['easy', 'medium', 'hard'][Math.floor(Math.random() * 3)]; |
| resetEnvironment(randomDifficulty); |
| }); |
|
|
| |
| let toastTimeout; |
| function showToast(title, message, isError = false) { |
| elements.toastTitle.textContent = title; |
| elements.toastMessage.textContent = message; |
| elements.toastMessage.style.color = isError ? 'var(--error)' : 'var(--success)'; |
| elements.toast.classList.remove('hidden'); |
| |
| clearTimeout(toastTimeout); |
| toastTimeout = setTimeout(hideToast, 4000); |
| } |
|
|
| function hideToast() { |
| elements.toast.classList.add('hidden'); |
| } |
|
|
| elements.toastClose.addEventListener('click', hideToast); |
|
|
| |
| resetEnvironment(); |
| }); |
|
|