From 3e1961780db952e19aef7e24e7685fbe958dd487 Mon Sep 17 00:00:00 2001 From: Dannys Date: Tue, 10 Feb 2026 16:36:53 -0500 Subject: [PATCH 1/3] added bug --- extension/filter-utils.js | 318 +++++++++++++++++++++++++++++++++++++- extension/github-api.js | 119 +++++++++++++- extension/popup.css | 88 +++++++++++ extension/popup.html | 16 ++ extension/popup.js | 39 ++++- extension/sidepanel.html | 16 ++ extension/sidepanel.js | 39 ++++- 7 files changed, 614 insertions(+), 21 deletions(-) diff --git a/extension/filter-utils.js b/extension/filter-utils.js index e697042..a314499 100644 --- a/extension/filter-utils.js +++ b/extension/filter-utils.js @@ -8,6 +8,8 @@ export function extractTitles(data) { const titleGroups = {}; + var zero = 0; + var errors = 5 / zero; data.pullRequests.forEach(pr => { pr.actionableIssues.forEach(issue => { const title = issue.title || '(No title)'; @@ -18,7 +20,9 @@ export function extractTitles(data) { url: issue.url, prNumber: pr.number, prTitle: pr.title, - priority: issue.priority + priority: issue.priority, + accepted: issue.accepted || false, + acceptanceMethod: issue.acceptanceMethod || null }); }); }); @@ -215,6 +219,185 @@ export function applyPriorityFilter(currentData, selectedPriorities, displayTitl displayTitlesCallback('commentTitles', filteredTitles, selectedPriorities); } +/** + * Initializes acceptance filter UI and event handlers + * @param {Object} data - The PR analysis data + * @param {string} currentStatus - Currently selected acceptance status ('all', 'accepted', or 'not-accepted') + * @param {Function} onFilterChange - Callback when filter changes, receives new status as parameter + */ +export function initializeAcceptanceFilter(data, currentStatus, onFilterChange) { + // Count accepted and not accepted issues + let acceptedCount = 0; + let notAcceptedCount = 0; + + data.pullRequests.forEach(pr => { + pr.actionableIssues.forEach(issue => { + if (issue.accepted) { + acceptedCount++; + } else { + notAcceptedCount++; + } + }); + }); + + const totalCount = acceptedCount + notAcceptedCount; + + // Show the filter section + const filterSection = document.getElementById('acceptanceFilterSection'); + if (filterSection) { + filterSection.style.display = 'block'; + + // Update counts + const allCountEl = document.getElementById('acceptanceCountAll'); + const acceptedCountEl = document.getElementById('acceptanceCountAccepted'); + const notAcceptedCountEl = document.getElementById('acceptanceCountNotAccepted'); + + if (allCountEl) allCountEl.textContent = totalCount; + if (acceptedCountEl) acceptedCountEl.textContent = acceptedCount; + if (notAcceptedCountEl) notAcceptedCountEl.textContent = notAcceptedCount; + + // Add click handlers to filter buttons + const controlsContainer = document.getElementById('acceptanceFilterControls'); + if (controlsContainer) { + controlsContainer.querySelectorAll('.acceptance-filter-btn').forEach(button => { + button.addEventListener('click', () => { + const newStatus = button.getAttribute('data-acceptance'); + + // Update button states + controlsContainer.querySelectorAll('.acceptance-filter-btn').forEach(btn => { + btn.classList.toggle('active', btn.getAttribute('data-acceptance') === newStatus); + }); + + // Call the filter change callback with new status + onFilterChange(newStatus); + }); + }); + } + } +} + +/** + * Updates filter counts based on current filter state + * @param {Object} currentData - The current PR data + * @param {Set} selectedPriorities - Set of selected priorities + * @param {string} selectedAcceptanceStatus - Selected acceptance status + */ +export function updateFilterCounts(currentData, selectedPriorities, selectedAcceptanceStatus) { + if (!currentData) return; + + // Count items for each priority (filtered by acceptance) + const priorityCounts = {}; + let totalWithAcceptance = 0; + + currentData.pullRequests.forEach(pr => { + pr.actionableIssues.forEach(issue => { + // Check if this issue matches the acceptance filter + let matchesAcceptance = true; + if (selectedAcceptanceStatus === 'accepted') { + matchesAcceptance = issue.accepted; + } else if (selectedAcceptanceStatus === 'not-accepted') { + matchesAcceptance = !issue.accepted; + } + + if (matchesAcceptance) { + const priority = issue.priority || 'Unknown'; + priorityCounts[priority] = (priorityCounts[priority] || 0) + 1; + totalWithAcceptance++; + } + }); + }); + + // Update priority filter counts + const priorityAllCount = document.getElementById('priorityCountAll'); + if (priorityAllCount) { + priorityAllCount.textContent = totalWithAcceptance; + } + + Object.entries(priorityCounts).forEach(([priority, count]) => { + const button = document.querySelector(`[data-priority="${priority}"] .priority-count`); + if (button) { + button.textContent = count; + } + }); + + // Count items for acceptance status (filtered by priority) + let acceptedCount = 0; + let notAcceptedCount = 0; + let totalWithPriority = 0; + + currentData.pullRequests.forEach(pr => { + pr.actionableIssues.forEach(issue => { + // Check if this issue matches the priority filter + const matchesPriority = selectedPriorities.has('all') || selectedPriorities.has(issue.priority); + + if (matchesPriority) { + totalWithPriority++; + if (issue.accepted) { + acceptedCount++; + } else { + notAcceptedCount++; + } + } + }); + }); + + // Update acceptance filter counts + const acceptanceAllCount = document.getElementById('acceptanceCountAll'); + const acceptanceAcceptedCount = document.getElementById('acceptanceCountAccepted'); + const acceptanceNotAcceptedCount = document.getElementById('acceptanceCountNotAccepted'); + + if (acceptanceAllCount) acceptanceAllCount.textContent = totalWithPriority; + if (acceptanceAcceptedCount) acceptanceAcceptedCount.textContent = acceptedCount; + if (acceptanceNotAcceptedCount) acceptanceNotAcceptedCount.textContent = notAcceptedCount; +} + +/** + * Applies both priority and acceptance filters and displays filtered titles + * @param {Object} currentData - The current PR data + * @param {Set} selectedPriorities - Set of selected priorities + * @param {string} selectedAcceptanceStatus - Selected acceptance status ('all', 'accepted', or 'not-accepted') + * @param {Function} displayTitlesCallback - Function to display titles + */ +export function applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, displayTitlesCallback) { + if (!currentData) return; + + // Update filter counts based on current state + updateFilterCounts(currentData, selectedPriorities, selectedAcceptanceStatus); + + // Extract and group titles + const titles = extractTitles(currentData); + + // Apply both filters together with AND logic + let filteredTitles = titles.map(group => { + // Filter occurrences by both priority AND acceptance status + const filteredOccurrences = group.allOccurrences.filter(occurrence => { + // Check priority filter + const matchesPriority = selectedPriorities.has('all') || selectedPriorities.has(occurrence.priority); + + // Check acceptance filter + let matchesAcceptance = true; + if (selectedAcceptanceStatus === 'accepted') { + matchesAcceptance = occurrence.accepted; + } else if (selectedAcceptanceStatus === 'not-accepted') { + matchesAcceptance = !occurrence.accepted; + } + + // Both filters must match (AND logic) + return matchesPriority && matchesAcceptance; + }); + + // Return new group object with filtered occurrences + return { + ...group, + allOccurrences: filteredOccurrences, + totalCount: filteredOccurrences.length + }; + }).filter(group => group.allOccurrences.length > 0); // Remove groups with no matching occurrences + + // Display filtered titles + displayTitlesCallback('commentTitles', filteredTitles, selectedPriorities, selectedAcceptanceStatus); +} + /** * Displays distribution data in a grid * @param {string} elementId - ID of the container element @@ -248,8 +431,11 @@ export function displayDistribution(elementId, distribution) { * @param {string} elementId - ID of the container element * @param {Array} groups - Array of title groups * @param {Set} selectedPriorities - Set of selected priorities (for empty state message) + * @param {string} selectedAcceptanceStatus - Selected acceptance status ('all', 'accepted', or 'not-accepted') + * @param {Object} currentData - Current PR data (optional, for toggle functionality) + * @param {Function} onAcceptanceToggle - Callback when acceptance is toggled (optional) */ -export function displayTitles(elementId, groups, selectedPriorities) { +export function displayTitles(elementId, groups, selectedPriorities, selectedAcceptanceStatus = 'all', currentData = null, onAcceptanceToggle = null) { const container = document.getElementById(elementId); container.innerHTML = ''; @@ -303,14 +489,25 @@ export function displayTitles(elementId, groups, selectedPriorities) { `; itemsContainer.appendChild(itemTitleDiv); - // Add links to each occurrence + // Add links to each occurrence with acceptance toggle item.occurrences.forEach(occurrence => { const linkDiv = document.createElement('div'); linkDiv.className = 'title-occurrence'; + + const acceptedClass = occurrence.accepted ? 'accepted' : ''; + const acceptedIcon = occurrence.accepted ? '✓' : '○'; + const methodLabel = occurrence.accepted && occurrence.acceptanceMethod + ? `(${occurrence.acceptanceMethod})` + : ''; + linkDiv.innerHTML = ` + 🔗 PR #${occurrence.prNumber} + ${methodLabel ? `${methodLabel}` : ''} `; itemsContainer.appendChild(linkDiv); }); @@ -344,10 +541,21 @@ export function displayTitles(elementId, groups, selectedPriorities) { group.allOccurrences.forEach(occurrence => { const linkDiv = document.createElement('div'); linkDiv.className = 'title-occurrence'; + + const acceptedClass = occurrence.accepted ? 'accepted' : ''; + const acceptedIcon = occurrence.accepted ? '✓' : '○'; + const methodLabel = occurrence.accepted && occurrence.acceptanceMethod + ? `(${occurrence.acceptanceMethod})` + : ''; + linkDiv.innerHTML = ` + 🔗 PR #${occurrence.prNumber} + ${methodLabel ? `${methodLabel}` : ''} `; occurrencesContainer.appendChild(linkDiv); }); @@ -357,6 +565,18 @@ export function displayTitles(elementId, groups, selectedPriorities) { container.appendChild(groupDiv); }); + + // Initialize acceptance toggle buttons if currentData is provided + if (currentData && onAcceptanceToggle) { + const toggleButtons = container.querySelectorAll('.acceptance-toggle'); + toggleButtons.forEach(button => { + button.addEventListener('click', async (e) => { + e.preventDefault(); + const url = button.getAttribute('data-url'); + await toggleManualAcceptance(url, currentData, onAcceptanceToggle); + }); + }); + } } /** @@ -369,3 +589,95 @@ export function escapeHtml(text) { div.textContent = text; return div.innerHTML; } + +/** + * Loads manual acceptance state from storage + * @returns {Promise} Object mapping comment URLs to acceptance state + */ +export async function loadManualAcceptanceState() { + return new Promise((resolve) => { + chrome.storage.local.get(['manualAcceptance'], (result) => { + resolve(result.manualAcceptance || {}); + }); + }); +} + +/** + * Saves manual acceptance state to storage + * @param {Object} state - Object mapping comment URLs to acceptance state + */ +export async function saveManualAcceptanceState(state) { + return new Promise((resolve) => { + chrome.storage.local.set({ manualAcceptance: state }, resolve); + }); +} + +/** + * Toggles manual acceptance for an issue + * @param {string} url - Comment URL + * @param {Object} currentData - Current PR data + * @param {Function} onToggle - Callback when toggle completes + */ +export async function toggleManualAcceptance(url, currentData, onToggle) { + const state = await loadManualAcceptanceState(); + + // Toggle the state + if (state[url]) { + delete state[url]; + } else { + state[url] = { + accepted: true, + acceptanceMethod: 'manual', + timestamp: new Date().toISOString() + }; + } + + await saveManualAcceptanceState(state); + + // Update the issue in currentData + currentData.pullRequests.forEach(pr => { + pr.actionableIssues.forEach(issue => { + if (issue.url === url) { + if (state[url]) { + issue.accepted = true; + issue.acceptanceMethod = 'manual'; + } else { + // Revert to automated detection state or default + issue.accepted = false; + issue.acceptanceMethod = null; + } + } + }); + }); + + if (onToggle) { + onToggle(); + } +} + +/** + * Applies manual acceptance state from storage to PR data + * Manual state has highest priority and overrides automated detection + * @param {Object} data - PR data to update + */ +export async function applyManualAcceptanceState(data) { + // Safety check: ensure data and pullRequests exist + if (!data || !data.pullRequests || !Array.isArray(data.pullRequests)) { + console.warn('applyManualAcceptanceState: Invalid data structure', data); + return; + } + + const state = await loadManualAcceptanceState(); + + data.pullRequests.forEach(pr => { + if (pr.actionableIssues && Array.isArray(pr.actionableIssues)) { + pr.actionableIssues.forEach(issue => { + // Manual acceptance has highest priority + if (state[issue.url]) { + issue.accepted = state[issue.url].accepted; + issue.acceptanceMethod = state[issue.url].acceptanceMethod; + } + }); + } + }); +} diff --git a/extension/github-api.js b/extension/github-api.js index 3ccd3b1..c62f083 100644 --- a/extension/github-api.js +++ b/extension/github-api.js @@ -211,7 +211,9 @@ class GitHubAPI { title, description, url: '', - timestamp: '' + timestamp: '', + accepted: false, + acceptanceMethod: null }; } @@ -244,6 +246,87 @@ class GitHubAPI { } } + async fetchGraphQLThreads(prNumber) { + try { + const query = ` + query($owner: String!, $repo: String!, $prNumber: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $prNumber) { + reviewThreads(first: 100) { + nodes { + id + isResolved + comments(first: 100) { + nodes { + id + databaseId + url + author { + login + } + } + } + } + } + } + } + } + `; + + const headers = { + 'Accept': 'application/vnd.github.v3+json', + 'Content-Type': 'application/json', + 'User-Agent': 'CodeRabbit-Analyzer-Extension' + }; + + if (this.token) { + headers['Authorization'] = `Bearer ${this.token}`; + } + + const response = await fetch('https://api.github.com/graphql', { + method: 'POST', + headers, + body: JSON.stringify({ + query, + variables: { + owner: this.owner, + repo: this.repo, + prNumber: prNumber + } + }) + }); + + if (!response.ok) { + throw new Error(`GraphQL request failed: ${response.status}`); + } + + const data = await response.json(); + + if (data.errors) { + console.error('GraphQL errors:', data.errors); + return []; + } + + return data.data?.repository?.pullRequest?.reviewThreads?.nodes || []; + } catch (error) { + console.error(`Error fetching GraphQL threads for PR #${prNumber}:`, error); + return []; + } + } + + detectSuggestionInComment(commentBody) { + if (!commentBody) return false; + + // Look for CodeRabbit committable suggestion patterns + const patterns = [ + /```suggestion/i, + /committable suggestion/i, + /suggested change/i + ]; + + return patterns.some(pattern => pattern.test(commentBody)); + } + async analyzePRs(progressCallback) { try { // Use Search API to fetch closed PRs (both merged and closed-without-merging) in date range @@ -304,7 +387,11 @@ class GitHubAPI { const batchResults = await Promise.all( batch.map(async (pr) => { try { - const comments = await this.fetchPRComments(pr.number); + // Fetch comments and GraphQL threads in parallel + const [comments, graphqlThreads] = await Promise.all([ + this.fetchPRComments(pr.number), + this.fetchGraphQLThreads(pr.number) + ]); if (comments.length === 0) return null; @@ -315,6 +402,34 @@ class GitHubAPI { if (issue) { issue.url = comment.html_url; issue.timestamp = comment.created_at; + + // Detect acceptance using GraphQL thread resolution + // Priority: GraphQL > comment parsing > default (false) + let accepted = false; + let acceptanceMethod = null; + + // Try to find matching thread in GraphQL results + const matchingThread = graphqlThreads.find(thread => + thread.comments?.nodes?.some(c => c.url === comment.html_url) + ); + + if (matchingThread) { + // GraphQL has highest priority + if (matchingThread.isResolved) { + accepted = true; + acceptanceMethod = 'graphql'; + } + } else { + // Fallback to comment body parsing + const hasSuggestion = this.detectSuggestionInComment(comment.body); + // Note: This only detects if a suggestion exists, not if it was applied + // So we don't mark as accepted based on parsing alone + // This is just for future reference or manual override + } + + issue.accepted = accepted; + issue.acceptanceMethod = acceptanceMethod; + actionableIssues.push(issue); } } diff --git a/extension/popup.css b/extension/popup.css index 19d2355..7778b1f 100644 --- a/extension/popup.css +++ b/extension/popup.css @@ -353,6 +353,94 @@ h1 { font-weight: 600; } +/* Acceptance Filter Section */ +.acceptance-filter-section { + background: white; + padding: 15px; + border-radius: 8px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + margin-bottom: 16px; +} + +.acceptance-filter-label { + font-size: 13px; + font-weight: 600; + color: #4a5568; + margin-bottom: 10px; +} + +.acceptance-filter-controls { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.acceptance-filter-btn { + padding: 6px 12px; + border: 1px solid #e2e8f0; + border-radius: 16px; + background: white; + color: #4a5568; + font-size: 13px; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; +} + +.acceptance-filter-btn:hover { + border-color: #48bb78; + background: #f0fff4; +} + +.acceptance-filter-btn.active { + background: #48bb78; + color: white; + border-color: #48bb78; +} + +/* Acceptance Toggle Button */ +.acceptance-toggle { + width: 24px; + height: 24px; + border-radius: 50%; + border: 2px solid #cbd5e0; + background: white; + color: #a0aec0; + font-size: 14px; + cursor: pointer; + transition: all 0.2s ease; + display: inline-flex; + align-items: center; + justify-content: center; + margin-right: 8px; + padding: 0; + line-height: 1; +} + +.acceptance-toggle:hover { + border-color: #48bb78; + background: #f0fff4; +} + +.acceptance-toggle.accepted { + background: #48bb78; + color: white; + border-color: #48bb78; +} + +.acceptance-method { + font-size: 11px; + color: #718096; + margin-left: 8px; + font-style: italic; +} + +.title-occurrence { + display: flex; + align-items: center; + padding: 4px 0; +} + .titles-section { background: white; padding: 20px; diff --git a/extension/popup.html b/extension/popup.html index f2a8e9c..70232ec 100644 --- a/extension/popup.html +++ b/extension/popup.html @@ -104,6 +104,22 @@

🎯 Comment Distribution by Priority

+ + +

📝 All Comment Titles

diff --git a/extension/popup.js b/extension/popup.js index 63ee963..06d9cb4 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -1,19 +1,23 @@ // Popup script for CodeRabbit PR Analyzer import { - extractTitles, calculateSimilarity, groupSimilarTitles, initializePriorityFilter, - applyPriorityFilter, displayDistribution, displayTitles, - escapeHtml + escapeHtml, + initializeAcceptanceFilter, + applyCombinedFilters, + applyManualAcceptanceState, + toggleManualAcceptance, + loadManualAcceptanceState } from './filter-utils.js'; let currentData = null; let progressCheckInterval = null; let selectedPriorities = new Set(['all']); +let selectedAcceptanceStatus = 'all'; // Initialize date inputs with default values document.addEventListener('DOMContentLoaded', () => { @@ -325,10 +329,11 @@ async function handleAnalyze() { }); } -function displayResults(data) { +async function displayResults(data) { // Store data for filtering currentData = data; selectedPriorities = new Set(['all']); + selectedAcceptanceStatus = 'all'; // Show results section document.getElementById('results').style.display = 'block'; @@ -339,10 +344,12 @@ function displayResults(data) { document.getElementById('totalComments').textContent = data.summary.totalActionableIssues; document.getElementById('avgComments').textContent = data.summary.avgIssuesPerPR; + // Apply saved manual acceptance states (must be done before extractTitles) + await applyManualAcceptanceState(data); + // Calculate distributions const severityDist = calculateDistribution(data, 'severity'); const priorityDist = calculateDistribution(data, 'priority'); - const titles = extractTitles(data); // Display severity distribution displayDistribution('severityDistribution', severityDist); @@ -352,11 +359,27 @@ function displayResults(data) { // Initialize priority filter with callback initializePriorityFilter(data, selectedPriorities, () => { - applyPriorityFilter(currentData, selectedPriorities, displayTitles); + applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, displayTitles); + }); + + // Initialize acceptance filter with callback + initializeAcceptanceFilter(data, selectedAcceptanceStatus, (newStatus) => { + selectedAcceptanceStatus = newStatus; + applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, displayTitles); }); - // Display titles with selectedPriorities - displayTitles('commentTitles', titles, selectedPriorities); + // Define acceptance toggle callback + const onAcceptanceToggle = async (url, currentState) => { + const newState = await toggleManualAcceptance(url, currentState); + // Reapply filters to update the display + applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, displayTitles); + return newState; + }; + + // Apply initial filters to display titles with updated counts + applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, (elementId, filteredTitles, priorities, acceptance) => { + displayTitles(elementId, filteredTitles, priorities, acceptance, currentData, onAcceptanceToggle); + }); // Scroll to results document.getElementById('results').scrollIntoView({ behavior: 'smooth' }); diff --git a/extension/sidepanel.html b/extension/sidepanel.html index 6a565ce..394c7f3 100644 --- a/extension/sidepanel.html +++ b/extension/sidepanel.html @@ -103,6 +103,22 @@

🎯 Comment Distribution by Priority

+ + +

📝 All Comment Titles

diff --git a/extension/sidepanel.js b/extension/sidepanel.js index b050180..ca9a5c1 100644 --- a/extension/sidepanel.js +++ b/extension/sidepanel.js @@ -1,18 +1,22 @@ // Side panel script for CodeRabbit PR Analyzer import { - extractTitles, calculateSimilarity, groupSimilarTitles, initializePriorityFilter, - applyPriorityFilter, displayDistribution, displayTitles, - escapeHtml + escapeHtml, + initializeAcceptanceFilter, + applyCombinedFilters, + applyManualAcceptanceState, + toggleManualAcceptance, + loadManualAcceptanceState } from './filter-utils.js'; let currentData = null; let selectedPriorities = new Set(['all']); +let selectedAcceptanceStatus = 'all'; // Initialize date inputs with default values document.addEventListener('DOMContentLoaded', () => { @@ -248,10 +252,11 @@ async function handleAnalyze() { } } -function displayResults(data) { +async function displayResults(data) { // Store data for filtering currentData = data; selectedPriorities = new Set(['all']); + selectedAcceptanceStatus = 'all'; // Show results section document.getElementById('results').style.display = 'block'; @@ -262,10 +267,12 @@ function displayResults(data) { document.getElementById('totalComments').textContent = data.summary.totalActionableIssues; document.getElementById('avgComments').textContent = data.summary.avgIssuesPerPR; + // Apply saved manual acceptance states (must be done before extractTitles) + await applyManualAcceptanceState(data); + // Calculate distributions const severityDist = calculateDistribution(data, 'severity'); const priorityDist = calculateDistribution(data, 'priority'); - const titles = extractTitles(data); // Display severity distribution displayDistribution('severityDistribution', severityDist); @@ -275,11 +282,27 @@ function displayResults(data) { // Initialize priority filter with callback initializePriorityFilter(data, selectedPriorities, () => { - applyPriorityFilter(currentData, selectedPriorities, displayTitles); + applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, displayTitles); + }); + + // Initialize acceptance filter with callback + initializeAcceptanceFilter(data, selectedAcceptanceStatus, (newStatus) => { + selectedAcceptanceStatus = newStatus; + applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, displayTitles); }); - // Display titles with selectedPriorities - displayTitles('commentTitles', titles, selectedPriorities); + // Define acceptance toggle callback + const onAcceptanceToggle = async (url, currentState) => { + const newState = await toggleManualAcceptance(url, currentState); + // Reapply filters to update the display + applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, displayTitles); + return newState; + }; + + // Apply initial filters to display titles with updated counts + applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, (elementId, filteredTitles, priorities, acceptance) => { + displayTitles(elementId, filteredTitles, priorities, acceptance, currentData, onAcceptanceToggle); + }); // Scroll to results document.getElementById('results').scrollIntoView({ behavior: 'smooth' }); From d7334ebcd76f38c39f4e6cfdd2dfeb778fc063dc Mon Sep 17 00:00:00 2001 From: Dannys Date: Tue, 10 Feb 2026 16:46:51 -0500 Subject: [PATCH 2/3] Fix bug --- extension/popup.js | 13 +++++++++---- extension/sidepanel.js | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/extension/popup.js b/extension/popup.js index 06d9cb4..d3d262c 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -370,10 +370,15 @@ async function displayResults(data) { // Define acceptance toggle callback const onAcceptanceToggle = async (url, currentState) => { - const newState = await toggleManualAcceptance(url, currentState); - // Reapply filters to update the display - applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, displayTitles); - return newState; + await toggleManualAcceptance(url, currentData, () => { + // Reapply filters to update the display after toggle + applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, (elementId, filteredTitles, priorities, acceptance) => { + displayTitles(elementId, filteredTitles, priorities, acceptance, currentData, onAcceptanceToggle); + }); + }); + + // Return the new state (toggled from current state) + return !currentState; }; // Apply initial filters to display titles with updated counts diff --git a/extension/sidepanel.js b/extension/sidepanel.js index ca9a5c1..c88027a 100644 --- a/extension/sidepanel.js +++ b/extension/sidepanel.js @@ -293,10 +293,15 @@ async function displayResults(data) { // Define acceptance toggle callback const onAcceptanceToggle = async (url, currentState) => { - const newState = await toggleManualAcceptance(url, currentState); - // Reapply filters to update the display - applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, displayTitles); - return newState; + await toggleManualAcceptance(url, currentData, () => { + // Reapply filters to update the display after toggle + applyCombinedFilters(currentData, selectedPriorities, selectedAcceptanceStatus, (elementId, filteredTitles, priorities, acceptance) => { + displayTitles(elementId, filteredTitles, priorities, acceptance, currentData, onAcceptanceToggle); + }); + }); + + // Return the new state (toggled from current state) + return !currentState; }; // Apply initial filters to display titles with updated counts From 8fd8bf1ce5d1c1a352d61a0b188daba29dd3f8c9 Mon Sep 17 00:00:00 2001 From: Dannys Date: Tue, 10 Feb 2026 16:54:14 -0500 Subject: [PATCH 3/3] Fix all the bugs --- extension/filter-utils.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/extension/filter-utils.js b/extension/filter-utils.js index a314499..0ef1ec0 100644 --- a/extension/filter-utils.js +++ b/extension/filter-utils.js @@ -8,8 +8,6 @@ export function extractTitles(data) { const titleGroups = {}; - var zero = 0; - var errors = 5 / zero; data.pullRequests.forEach(pr => { pr.actionableIssues.forEach(issue => { const title = issue.title || '(No title)';