Analysis Pipeline Builder

${stage.description}

`; // Add connector and "add" button, but not after the last stage if (index < pipelineData.length) { pipelineContainer.innerHTML += `
+
`; } // Remove the last two connectors if (index === pipelineData.length -1) { const elements = pipelineContainer.getElementsByClassName('ap-connector'); const lastConnector = elements[elements.length-1] const secondToLastConnector = elements[elements.length-2] lastConnector?.parentNode?.removeChild(lastConnector); secondToLastConnector?.parentNode?.removeChild(secondToLastConnector); const addButtons = pipelineContainer.getElementsByClassName('ap-add-stage-btn'); const lastAddButton = addButtons[addButtons.length - 1]; lastAddButton?.parentNode?.removeChild(lastAddButton); } }); pipelineWrapper.innerHTML = ''; // Clear previous render pipelineWrapper.appendChild(pipelineContainer); } // --- EVENT HANDLING (using event delegation) --- pipelineWrapper.addEventListener('click', function(event) { const target = event.target; const action = target.dataset.action; if (action === 'add') { const index = parseInt(target.dataset.index); addStage(index); } else if (action === 'remove') { const id = parseInt(target.dataset.id); removeStage(id); } else if (action === 'edit') { makeEditable(target); } }); pipelineWrapper.addEventListener('change', function(event) { const target = event.target; const action = target.dataset.action; if(action === 'status-change') { const id = parseInt(target.dataset.id); const newStatus = target.value; updateStatus(id, newStatus); } }); // --- ACTION FUNCTIONS --- function addStage(index) { const newId = pipelineData.length > 0 ? Math.max(...pipelineData.map(s => s.id)) + 1 : 1; const newStage = { id: newId, title: 'New Stage', description: 'Click to edit description.', status: 'Not Started' }; pipelineData.splice(index, 0, newStage); renderPipeline(); } function removeStage(id) { if (confirm('Are you sure you want to remove this stage?')) { pipelineData = pipelineData.filter(stage => stage.id !== id); renderPipeline(); } } function updateStatus(id, newStatus) { const stage = pipelineData.find(s => s.id === id); if (stage) { stage.status = newStatus; renderPipeline(); } } function makeEditable(element) { element.setAttribute('contenteditable', 'true'); element.focus(); element.addEventListener('blur', saveEdit, { once: true }); element.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); element.blur(); } }); } function saveEdit(event) { const element = event.target; element.setAttribute('contenteditable', 'false'); const id = parseInt(element.closest('.ap-stage').dataset.id); const key = element.dataset.key; const newValue = element.textContent; const stage = pipelineData.find(s => s.id === id); if (stage && stage[key] !== undefined) { stage[key] = newValue; } // No re-render needed for contenteditable, avoids losing focus state } // --- PDF DOWNLOAD --- downloadBtn.addEventListener('click', async function() { const originalButtonText = downloadBtn.textContent; downloadBtn.textContent = 'Generating...'; downloadBtn.disabled = true; const pipelineElement = document.querySelector('.ap-pipeline'); if (!pipelineElement) { alert('Pipeline is empty. Nothing to download.'); downloadBtn.textContent = originalButtonText; downloadBtn.disabled = false; return; } const canvas = await html2canvas(pipelineElement, { scale: 2, logging: false, useCORS: true, scrollX: 0, scrollY: -window.scrollY }); const imgData = canvas.toDataURL('image/png'); const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: 'landscape', unit: 'px', format: [canvas.width, canvas.height] }); pdf.addImage(imgData, 'PNG', 0, 0, canvas.width, canvas.height); pdf.save('Analysis_Pipeline.pdf'); downloadBtn.textContent = originalButtonText; downloadBtn.disabled = false; }); // --- INITIAL RENDER --- renderPipeline(); });
Scroll to Top