Bug Finder Tool

Bug Finder Tool

To Do

In Progress

Done

Add a New Bug

Bug deleted.

'; // But for this spec, we'll filter and re-render. // bugs = bugs.filter((bug) => bug.id !== bugId); // renderDashboard(); } } } /** * Handles edits made directly to cards (inputs, textareas, selects) * @param {Event} e - The input or change event */ function handleCardUpdate(e) { const field = e.target.dataset.field; if (!field) return; // Not an editable field const card = e.target.closest(".bft-bug-card"); if (!card) return; const bugId = card.dataset.id; const bug = findBugById(bugId); if (!bug) return; // Update the bug object in our state bug[field] = e.target.value; // Special case: If priority changed, update border if (field === 'priority') { card.className = `bft-bug-card priority-${bug.priority}`; } // Special case: If status changed, move the card if (field === "status") { // A simple re-render will move it renderDashboard(); } } /** * Generates a PDF report of all bugs */ function downloadPDF() { if ( typeof window.jspdf === "undefined" || typeof window.jspdf.jsPDF.autoTable === "undefined" ) { console.error("jsPDF or jsPDF-AutoTable is not loaded."); // Use a simple, non-blocking modal for this. alert("Error: PDF library could not be loaded. Please check your internet connection."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF("p", "pt", "a4"); const tableHead = [ "ID", "Title", "Status", "Priority", "Assignee", "Description", ]; const tableBody = bugs.map((bug) => [ bug.id.substring(0, 10), // Shorten ID for PDF bug.title, bug.status, bug.priority, bug.assignee, bug.desc, ]); doc.setFontSize(18); doc.text("Bug Tracker Report", 40, 40); doc.autoTable({ startY: 50, head: tableHead, body: tableBody, theme: "striped", headStyles: { fillColor: [0, 115, 230], textColor: [255, 255, 255], }, columnStyles: { 0: { cellWidth: 60 }, 1: { cellWidth: 100 }, 2: { cellWidth: 50 }, 3: { cellWidth: 50 }, 4: { cellWidth: 70 }, 5: { cellWidth: "auto" }, }, }); doc.save("Bug_Tracker_Report.pdf"); } /** * Switches between tabs * @param {string} targetTabId - The ID of the tab pane to show */ function showTab(targetTabId) { if (!targetTabId) return; const targetPane = bftContainer.querySelector("#" + targetTabId); const targetButton = bftContainer.querySelector( `.bft-tab-btn[data-target="${targetTabId}"]` ); if (!targetPane || !targetButton) return; tabPanes.forEach((pane) => pane.classList.remove("active")); tabButtons.forEach((btn) => btn.classList.remove("active")); targetPane.classList.add("active"); targetButton.classList.add("active"); } /** * Helper to escape HTML to prevent XSS */ function escapeHTML(str) { if (!str) return ""; return str .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } // --- 3. INITIALIZATION & EVENT LISTENERS --- // Tab Listeners tabButtons.forEach((btn) => { btn.addEventListener("click", () => showTab(btn.dataset.target)); }); navButtons.forEach((btn) => { btn.addEventListener("click", () => showTab(btn.dataset.target)); }); // Form Listener if (configForm) { configForm.addEventListener("submit", addNewBug); } // Dashboard Listeners (Event Delegation) if (dashboardColumns) { dashboardColumns.addEventListener("click", handleDashboardClick); dashboardColumns.addEventListener("change", handleCardUpdate); // For &