// Dashboard functionality let jobs = []; let currentJob = null; // Initialize dashboard document.addEventListener('DOMContentLoaded', function() { initFileUpload(); initJobsTable(); loadSampleJobs(); }); // File upload functionality function initFileUpload() { const dropZone = document.getElementById('drop-zone'); const fileInput = document.getElementById('file-input'); // Handle drag and drop dropZone.addEventListener('dragover', function(e) { e.preventDefault(); dropZone.classList.add('dragover'); }); dropZone.addEventListener('dragleave', function(e) { e.preventDefault(); dropZone.classList.remove('dragover'); }); dropZone.addEventListener('drop', function(e) { e.preventDefault(); dropZone.classList.remove('dragover'); const files = Array.from(e.dataTransfer.files); handleFileUpload(files); }); // Handle file input fileInput.addEventListener('change', function(e) { const files = Array.from(e.target.files); handleFileUpload(files); }); // Handle click to upload dropZone.addEventListener('click', function() { fileInput.click(); }); } // Handle file upload async function handleFileUpload(files) { if (files.length === 0) return; // Hide drop zone when files are uploaded document.getElementById('drop-zone').style.display = 'none'; for (const file of files) { const job = createJob(file); jobs.unshift(job); try { // Show processing updateJobStatus(job.id, 'processing'); // Simulate API call const result = await Wash.mockAPI.cleanDocument(file); // Update job with results updateJobWithResult(job.id, result); } catch (error) { updateJobStatus(job.id, 'failed', error.message); } } renderJobsTable(); } // Create new job function createJob(file) { return { id: Date.now() + Math.random(), fileName: file.name, fileSize: Wash.formatBytes(file.size), status: 'queued', threats: [], processingTime: 0, createdAt: new Date(), output: {} }; } // Update job status function updateJobStatus(jobId, status, error = null) { const job = jobs.find(j => j.id === jobId); if (job) { job.status = status; if (error) { job.error = error; } renderJobsTable(); } } // Update job with API result function updateJobWithResult(jobId, result) { const job = jobs.find(j => j.id === jobId); if (job) { job.status = 'completed'; job.threats = result.threats; job.processingTime = result.processingTime; job.output = { text: result.cleanText, pdf: result.cleanPDF, json: JSON.stringify(result.metadata, null, 2) }; job.metadata = result.metadata; renderJobsTable(); } } // Initialize jobs table function initJobsTable() { // Add click handlers for job rows document.addEventListener('click', function(e) { const row = e.target.closest('tr[data-job-id]'); if (row) { const jobId = parseFloat(row.dataset.jobId); showJobDetails(jobId); } }); } // Load sample jobs function loadSampleJobs() { const sampleJobs = [ { id: 1, fileName: 'contract.pdf', fileSize: '245 KB', status: 'completed', threats: ['zero-width characters', 'embedded JavaScript', 'LSB steganography'], processingTime: 4.2, createdAt: new Date(Date.now() - 3600000), output: { text: 'Clean contract text...', pdf: 'blob:contract-clean', json: '{"originalSize": 250880, "cleanedSize": 213248, "threatsRemoved": 3}' }, metadata: { originalSize: 250880, cleanedSize: 213248, threatsRemoved: 3 } }, { id: 2, fileName: 'resume.docx', fileSize: '89 KB', status: 'completed', threats: ['VBA macro'], processingTime: 3.1, createdAt: new Date(Date.now() - 7200000), output: { text: 'Clean resume text...', pdf: 'blob:resume-clean', json: '{"originalSize": 91136, "cleanedSize": 87432, "threatsRemoved": 1}' }, metadata: { originalSize: 91136, cleanedSize: 87432, threatsRemoved: 1 } }, { id: 3, fileName: 'image.png', fileSize: '1.2 MB', status: 'completed', threats: ['LSB stego in blue channel'], processingTime: 1.9, createdAt: new Date(Date.now() - 10800000), output: { text: 'Extracted image text...', pdf: 'blob:image-clean', json: '{"originalSize": 1258291, "cleanedSize": 1193862, "threatsRemoved": 1}' }, metadata: { originalSize: 1258291, cleanedSize: 1193862, threatsRemoved: 1 } }, { id: 4, fileName: 'memo.pdf', fileSize: '156 KB', status: 'processing', threats: [], processingTime: 0, createdAt: new Date(Date.now() - 300000), output: {} } ]; jobs = sampleJobs; renderJobsTable(); } // Render jobs table function renderJobsTable() { const tableBody = document.getElementById('jobs-table'); if (jobs.length === 0) { document.getElementById('drop-zone').style.display = 'block'; return; } document.getElementById('drop-zone').style.display = 'none'; tableBody.innerHTML = jobs.map(job => { const timeAgo = getTimeAgo(job.createdAt); const statusClass = getStatusClass(job.status); const statusText = getStatusText(job.status); return `
This document contains zero-width characters and embedded JavaScript code.
This document contains zero-width characters and embedded JavaScript code.
Processing your document...
` : `Job details will appear here when processing is complete.
`}