const fileInput = document.getElementById('local-file'); const pathInput = document.getElementById('findings_path'); let currentRawData = null; let isJson = false; fileInput.addEventListener('change', (e) => { const file = e.target.files[0]; if (!file) return; isJson = file.name.toLowerCase().endsWith('.json'); const reader = new FileReader(); reader.onload = (event) => { currentRawData = event.target.result; document.getElementById('preview-placeholder').style.display = 'none'; if (isJson) { try { const parsed = JSON.parse(currentRawData); const guessedPath = autoDetectArrayPath(parsed); if (guessedPath) { pathInput.value = guessedPath; } } catch (e) { console.error("Auto-detect failed:", e); } } processPreview(); }; reader.readAsText(file); }); pathInput.addEventListener('input', () => { if (currentRawData && isJson) processPreview(); }); function autoDetectArrayPath(obj) { if (Array.isArray(obj)) return "."; let bestPath = ""; let maxLen = -1; function search(currentObj, currentPath) { if (Array.isArray(currentObj)) { if (currentObj.length > 0 && typeof currentObj[0] === 'object') { if (currentObj.length > maxLen) { maxLen = currentObj.length; bestPath = currentPath; } } return; } if (currentObj !== null && typeof currentObj === 'object') { for (let key in currentObj) { let nextPath = currentPath ? currentPath + "." + key : key; search(currentObj[key], nextPath); } } } search(obj, ""); return bestPath || "."; } function processPreview() { let headers = []; let rows = []; if (isJson) { try { const parsed = JSON.parse(currentRawData); const findings = getNestedValue(parsed, pathInput.value); if (!Array.isArray(findings) || findings.length === 0) { const rawPreview = JSON.stringify(parsed, null, 2).substring(0, 1500) + "\n\n... (file truncated for preview)"; document.getElementById('preview-table-container').innerHTML = `

⚠️ Path "${pathInput.value}" is not an array.

Here is the structure of your file to help you find the correct path:

${rawPreview}
`; document.getElementById('save-btn').classList.add('disabled'); return; } document.getElementById('save-btn').classList.remove('disabled'); headers = Object.keys(findings[0]); rows = findings.slice(0, 5).map(obj => headers.map(h => formatCell(obj[h]))); } catch(e) { document.getElementById('preview-table-container').innerHTML = `
JSON Parse Error: ${e.message}
`; return; } } else { const lines = currentRawData.split('\n').filter(l => l.trim() !== ''); headers = lines[0].split(',').map(h => h.trim()); rows = lines.slice(1, 6).map(line => line.split(',').map(c => c.trim())); document.getElementById('save-btn').classList.remove('disabled'); } renderTable(headers, rows); populateDropdowns(headers); } function getNestedValue(obj, path) { if (path === '' || path === '.') return obj; return path.split('.').reduce((acc, part) => acc && acc[part], obj); } function formatCell(val) { if (typeof val === 'object') return JSON.stringify(val); if (val === undefined || val === null) return ""; const str = String(val); return str.length > 50 ? str.substring(0, 47) + "..." : str; } function renderTable(headers, rows) { let html = ''; html += '' + headers.map(h => ``).join('') + ''; rows.forEach(row => { html += '' + row.map(cell => ``).join('') + ''; }); html += '
${h}
${cell}
'; document.getElementById('preview-table-container').innerHTML = html; } function populateDropdowns(headers) { const selects = document.querySelectorAll('.source-header'); selects.forEach(select => { select.innerHTML = ''; headers.forEach(h => { const opt = document.createElement('option'); opt.value = h; opt.textContent = h; select.appendChild(opt); }); }); } document.getElementById('adapter-form').onsubmit = async (e) => { e.preventDefault(); const data = { name: document.getElementById('name').value, source_name: document.getElementById('source_name').value, findings_path: document.getElementById('findings_path').value, mapping_title: document.getElementById('mapping_title').value, mapping_asset: document.getElementById('mapping_asset').value, mapping_severity: document.getElementById('mapping_severity').value, mapping_description: document.getElementById('mapping_description').value, mapping_remediation: document.getElementById('mapping_remediation').value }; const resp = await fetch('/api/adapters', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); if (resp.ok) { alert("Adapter Saved! Taking you back to the Landing Zone."); window.location.href = "/ingest"; } else { alert("Failed to save adapter: " + await resp.text()); } }; window.exportAdapterJSON = function() { const name = document.getElementById("adapterName").value.trim(); const sourceName = document.getElementById("sourceName").value.trim(); const rootPath = document.getElementById("rootPath").value.trim(); if (!name || !sourceName) { return alert("Adapter Name and Source Name are required to export."); } const payload = { name: name, source_name: sourceName, findings_path: rootPath, mapping_title: document.getElementById("mapTitle").value.trim(), mapping_asset: document.getElementById("mapAsset").value.trim(), mapping_severity: document.getElementById("mapSeverity").value.trim(), mapping_description: document.getElementById("mapDesc").value.trim(), mapping_remediation: document.getElementById("mapRem").value.trim() }; // Create a downloadable JSON blob const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(payload, null, 4)); const downloadAnchorNode = document.createElement('a'); downloadAnchorNode.setAttribute("href", dataStr); downloadAnchorNode.setAttribute("download", `${sourceName.toLowerCase().replace(/\s+/g, '_')}_adapter.json`); document.body.appendChild(downloadAnchorNode); downloadAnchorNode.click(); downloadAnchorNode.remove(); };