diff --git a/src/components/miners/MinerOpenDiscoveryIssuesByRepo.tsx b/src/components/miners/MinerOpenDiscoveryIssuesByRepo.tsx index f2ad7704..01faa1c0 100644 --- a/src/components/miners/MinerOpenDiscoveryIssuesByRepo.tsx +++ b/src/components/miners/MinerOpenDiscoveryIssuesByRepo.tsx @@ -193,6 +193,20 @@ const getIssueCounts = (issues: RepositoryIssue[]) => ({ closed: issues.filter(isClosedIssue).length, }); +const applyIssueSearch = ( + issues: RepositoryIssue[], + search: string, +): RepositoryIssue[] => { + const q = search.trim().toLowerCase(); + if (!q) return issues; + return issues.filter( + (i) => + i.title.toLowerCase().includes(q) || + i.repositoryFullName.toLowerCase().includes(q) || + String(i.number).includes(q), + ); +}; + const applyIssueFilter = ( issues: RepositoryIssue[], filter: IssueFilter, @@ -204,15 +218,7 @@ const applyIssueFilter = ( if (filter === 'open') result = result.filter(isOpenIssue); else if (filter === 'solved') result = result.filter(isSolvedIssue); else if (filter === 'closed') result = result.filter(isClosedIssue); - const q = search.trim().toLowerCase(); - if (q) { - result = result.filter( - (i) => - i.title.toLowerCase().includes(q) || - i.repositoryFullName.toLowerCase().includes(q) || - String(i.number).includes(q), - ); - } + result = applyIssueSearch(result, search); return [...result].sort((a, b) => { let cmp = 0; if (sortField === 'number') cmp = a.number - b.number; @@ -426,8 +432,16 @@ const MinerOpenDiscoveryIssuesByRepo: React.FC< const mineTotalPages = Math.ceil(filteredMine.length / PAGE_SIZE); const otherTotalPages = Math.ceil(filteredOther.length / PAGE_SIZE); - const mineCounts = useMemo(() => getIssueCounts(mineIssues), [mineIssues]); - const otherCounts = useMemo(() => getIssueCounts(otherIssues), [otherIssues]); + // Count over the search scope (excluding the active status filter) so each + // button reflects what the user would see if they clicked it. + const mineCounts = useMemo( + () => getIssueCounts(applyIssueSearch(mineIssues, mineSearch)), + [mineIssues, mineSearch], + ); + const otherCounts = useMemo( + () => getIssueCounts(applyIssueSearch(otherIssues, otherSearch)), + [otherIssues, otherSearch], + ); const mineColumns: DataTableColumn[] = useMemo( diff --git a/src/components/miners/MinerPRsTable.tsx b/src/components/miners/MinerPRsTable.tsx index 6180f39e..8ba4a9e5 100644 --- a/src/components/miners/MinerPRsTable.tsx +++ b/src/components/miners/MinerPRsTable.tsx @@ -215,10 +215,18 @@ const MinerPRsTable: React.FC = ({ githubId }) => { const totalPages = Math.ceil(sortedPRs.length / PAGE_SIZE); + // Count over the search + author scope (excluding the active status filter) + // so each button reflects what the user would see if they clicked it. const statusCounts = useMemo(() => { if (!prs) return { all: 0, open: 0, merged: 0, closed: 0 }; - return getPrStatusCounts(prs); - }, [prs]); + const scope = filterPrs(prs, { + author: selectedAuthor, + includeNumber: true, + searchQuery, + statusFilter: 'all', + }); + return getPrStatusCounts(scope); + }, [prs, selectedAuthor, searchQuery]); const hasFilters = Boolean(selectedAuthor) || diff --git a/src/components/miners/MinerRepositoriesTable.tsx b/src/components/miners/MinerRepositoriesTable.tsx index 0a4aea05..ac35eee3 100644 --- a/src/components/miners/MinerRepositoriesTable.tsx +++ b/src/components/miners/MinerRepositoriesTable.tsx @@ -130,23 +130,25 @@ const MinerRepositoriesTable: React.FC = ({ } }, [issueRepoStats, statusFilter]); - const repoStatusCounts = useMemo( - () => ({ - all: repoStats.length, - recent: repoStats.filter(isRecentRepoStats).length, - stale: repoStats.filter(isStaleRepoStats).length, - }), - [repoStats], - ); - - const issueRepoStatusCounts = useMemo( - () => ({ - all: issueRepoStats.length, - recent: issueRepoStats.filter(isRecentIssueRepoStats).length, - stale: issueRepoStats.filter(isStaleIssueRepoStats).length, - }), - [issueRepoStats], - ); + // Count over the search scope (excluding the active status filter) so each + // button reflects what the user would see if they clicked it. + const repoStatusCounts = useMemo(() => { + const scope = filterBySearch(repoStats, searchQuery); + return { + all: scope.length, + recent: scope.filter(isRecentRepoStats).length, + stale: scope.filter(isStaleRepoStats).length, + }; + }, [repoStats, searchQuery]); + + const issueRepoStatusCounts = useMemo(() => { + const scope = filterBySearch(issueRepoStats, searchQuery); + return { + all: scope.length, + recent: scope.filter(isRecentIssueRepoStats).length, + stale: scope.filter(isStaleIssueRepoStats).length, + }; + }, [issueRepoStats, searchQuery]); const filteredRepoStats = useMemo( () => filterBySearch(statusFilteredRepoStats, searchQuery), diff --git a/src/components/miners/MinerScoreBreakdown.tsx b/src/components/miners/MinerScoreBreakdown.tsx index cc3a767c..0b54f44e 100644 --- a/src/components/miners/MinerScoreBreakdown.tsx +++ b/src/components/miners/MinerScoreBreakdown.tsx @@ -1037,7 +1037,19 @@ const PrBreakdownView: React.FC<{ githubId: string }> = ({ githubId }) => { if (!isMobile) setIsMobileSearchOpen(false); }, [isMobile]); - const statusCounts = useMemo(() => getPrStatusCounts(prs ?? []), [prs]); + // Count over the search scope (excluding the active status filter) so each + // button reflects what the user would see if they clicked it. + const statusCounts = useMemo( + () => + getPrStatusCounts( + filterPrs(prs ?? [], { + searchQuery, + includeNumber: true, + statusFilter: 'all', + }), + ), + [prs, searchQuery], + ); const statusFilterTotal = useMemo(() => { switch (statusFilter) {