diff --git a/static/js/debugging.js b/static/js/debugging.js new file mode 100644 index 0000000..3c59623 --- /dev/null +++ b/static/js/debugging.js @@ -0,0 +1,221 @@ +// File system sync functionality +document.getElementById('syncFilesBtn').addEventListener('click', async function() { + const btn = this; + const status = document.getElementById('syncStatus'); + + // Disable button and show loading state + btn.disabled = true; + btn.innerHTML = ' Syncing...'; + status.textContent = 'Syncing file system...'; + + try { + const response = await fetch('/api/admin/sync-files', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') + } + }); + + console.log('Sync response status:', response.status); + console.log('Sync response headers:', Object.fromEntries(response.headers.entries())); + + const responseText = await response.text(); + console.log('Sync response text:', responseText); + + let data; + try { + data = JSON.parse(responseText); + console.log('Parsed sync response:', data); + } catch (parseError) { + console.error('JSON parse error:', parseError); + throw new Error('Invalid response format from server'); + } + + if (response.ok) { + status.textContent = 'Sync completed successfully!'; + status.className = 'text-success small'; + } else { + throw new Error(data.error || 'Sync failed'); + } + } catch (error) { + console.error('Sync error:', error); + status.textContent = error.message; + status.className = 'text-danger small'; + } finally { + // Reset button state + btn.disabled = false; + btn.innerHTML = ' Sync File System'; + + // Clear status after 5 seconds + setTimeout(() => { + status.textContent = ''; + status.className = 'text-muted small'; + }, 5000); + } +}); + +// Database verification functionality +document.getElementById('verifyDbBtn').addEventListener('click', async function() { + const btn = this; + const status = document.getElementById('verifyStatus'); + const results = document.getElementById('verificationResults'); + + // Disable button and show loading state + btn.disabled = true; + btn.innerHTML = ' Verifying...'; + status.textContent = 'Verifying database state...'; + results.style.display = 'none'; + + try { + const response = await fetch('/api/admin/verify-db-state', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') + } + }); + + const data = await response.json(); + console.log('Verification response:', data); + + if (!response.ok) { + throw new Error(data.error || 'Verification failed'); + } + + // Update summary + const summary = document.getElementById('verificationSummary'); + const totalIssues = (data.files_in_db_not_fs?.length || 0) + + (data.files_in_fs_not_db?.length || 0) + + (data.size_mismatches?.length || 0) + + (data.modified_time_mismatches?.length || 0); + + summary.textContent = `Found ${totalIssues} issues across ${data.rooms_checked || 0} rooms.`; + + // Update counts and lists + updateMismatchSection('dbNotFs', data.files_in_db_not_fs || []); + updateMismatchSection('fsNotDb', data.files_in_fs_not_db || []); + updateMismatchSection('sizeMismatch', data.size_mismatches || []); + updateMismatchSection('timeMismatch', data.modified_time_mismatches || []); + + // Show results + results.style.display = 'block'; + status.textContent = 'Verification completed!'; + status.className = 'text-success small'; + } catch (error) { + console.error('Verification error:', error); + status.textContent = error.message; + status.className = 'text-danger small'; + } finally { + // Reset button state + btn.disabled = false; + btn.innerHTML = ' Verify Database State'; + } +}); + +// Cleanup orphaned records functionality +document.getElementById('cleanupOrphanedBtn').addEventListener('click', async function() { + const btn = this; + const status = document.getElementById('verifyStatus'); + + // Disable button and show loading state + btn.disabled = true; + btn.innerHTML = ' Cleaning up...'; + status.textContent = 'Cleaning up orphaned records...'; + + try { + const response = await fetch('/api/admin/cleanup-orphaned-records', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') + } + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.error || 'Cleanup failed'); + } + + status.textContent = data.message; + status.className = 'text-success small'; + + // If there were cleaned records, trigger a verification + if (data.cleaned_records && data.cleaned_records.length > 0) { + document.getElementById('verifyDbBtn').click(); + } + } catch (error) { + console.error('Cleanup error:', error); + status.textContent = error.message; + status.className = 'text-danger small'; + } finally { + // Reset button state + btn.disabled = false; + btn.innerHTML = ' Cleanup Orphaned Records'; + + // Clear status after 5 seconds + setTimeout(() => { + status.textContent = ''; + status.className = 'text-muted small'; + }, 5000); + } +}); + +// Helper function to update mismatch sections +function updateMismatchSection(sectionId, items) { + const count = document.getElementById(`${sectionId}Count`); + const list = document.getElementById(`${sectionId}List`); + + if (!count || !list) { + console.error(`Missing elements for section ${sectionId}`); + return; + } + + count.textContent = items.length; + + if (items.length === 0) { + list.innerHTML = '