Skip to content

feat(dashboard): add PRs page with project filter and run counts#688

Merged
aaight merged 2 commits intodevfrom
feature/prs-dashboard-page
Mar 9, 2026
Merged

feat(dashboard): add PRs page with project filter and run counts#688
aaight merged 2 commits intodevfrom
feature/prs-dashboard-page

Conversation

@aaight
Copy link
Copy Markdown
Collaborator

@aaight aaight commented Mar 9, 2026

Summary

  • Add new /prs route page listing all PRs with PR number (clickable GitHub link), title, linked work item (clickable link), and run count
  • Add prs-table.tsx component following the workitems-table.tsx pattern with pagination and empty state
  • Add "PRs" nav link to sidebar using GitPullRequest lucide icon
  • Update prs.list tRPC endpoint to support optional projectId (shows all org PRs when omitted)
  • Update listPRsForProject and listPRsForWorkItem repository functions to include runCount via JOIN with agentRuns
  • Add listPRsForOrg repository function for cross-project PR listing

Test plan

  • Navigate to /prs — page loads and shows all PRs
  • PR number links to GitHub PR URL (opens in new tab)
  • Work item title links to external work item URL (opens in new tab)
  • PRs without linked work items show "Unlinked" label
  • Project filter dropdown filters PRs by project
  • Pagination works when > 50 PRs exist
  • "PRs" link visible in sidebar and navigates correctly
  • All 4261 tests passing, lint clean, type checks pass

Closes https://trello.com/c/69adf50de48c9db558e6aa7d

🤖 Generated with Claude Code

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Clean implementation that follows existing patterns well (mirrors workitems page closely). Two issues worth addressing — one correctness bug with React keys and one missing test coverage for the new code path.

Code Issues

Should Fix

  • web/src/components/prs/prs-table.tsx:46key={item.prNumber} will produce duplicate React keys in the org-wide ("All projects") view. The prNumber is unique per project (via UNIQUE(projectId, prNumber) constraint), but when listPRsForOrg aggregates across projects, two different repos can both have PR #1. The GROUP BY correctly produces separate rows (due to different repoFullName), but React will see duplicate keys and may exhibit incorrect rendering/update behavior. Consider using a composite key like key={`${item.repoFullName}-${item.prNumber}`}.

  • web/src/routes/prs.tsx / web/src/components/prs/prs-table.tsx — In the org-wide view, PRs from different repositories are indistinguishable. The repoFullName is returned by the backend but never displayed. When a user selects "All projects", two PRs with the same number from different repos would appear identical. Consider showing repoFullName as a secondary label, at least when no project filter is active.

  • tests/unit/api/routers/prs.test.ts — The unit test mock setup (line 14-17) does not include listPRsForOrg, and there are no tests for the list({}) / list({ projectId: undefined }) code path (org-wide query). The new branch in the router where projectId is omitted is completely untested. The mock at line 14 will cause the import to fail or listPRsForOrg to be undefined when invoked.

</tr>
)}
{pageItems.map((item) => (
<tr
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[SHOULD_FIX] key={item.prNumber} will produce duplicate React keys in the org-wide view. prNumber is only unique within a project (UNIQUE(projectId, prNumber)), so two repos can both have PR #1. This causes incorrect React reconciliation.

Fix: use a composite key:

key={`${item.repoFullName}-${item.prNumber}`}

Also consider: repoFullName is not shown in the table but is available from the backend — when viewing "All projects", users can't distinguish which repo a PR belongs to.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed! Changed the React key to use a composite key ${item.repoFullName}-${item.prNumber} to ensure uniqueness across different repositories in the org-wide view.

Also added a showRepoName prop to the table that displays the repository name in a separate column when viewing "All projects" (when no project filter is active). This makes it clear which repo each PR belongs to.

Comment thread src/api/routers/prs.ts
await verifyProjectOrgAccess(input.projectId, ctx.effectiveOrgId);
return listPRsForProject(input.projectId);
}
return listPRsForOrg(ctx.effectiveOrgId);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[SHOULD_FIX] The listPRsForOrg path is not covered by unit tests. The mock setup in prs.test.ts doesn't mock listPRsForOrg, so calling list({}) (no projectId) would hit an undefined function. Add a test case for the org-wide path and mock listPRsForOrg.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed! Added listPRsForOrg to the mock setup and created a new test case "returns PRs across all projects when no projectId given" that tests the org-wide query path. The test verifies that when list({}) is called without a projectId, it calls listPRsForOrg with the org ID and skips the project access verification.

- Fix duplicate React keys by using composite key (repoFullName + prNumber)
- Add repoFullName column when viewing all projects to distinguish PRs from different repos
- Add missing listPRsForOrg mock and test coverage for org-wide query path

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@aaight
Copy link
Copy Markdown
Collaborator Author

aaight commented Mar 9, 2026

Review Feedback Addressed

All review feedback has been addressed and changes have been pushed:

Changes Made

  1. Fixed duplicate React keys (web/src/components/prs/prs-table.tsx) - Changed from key={item.prNumber} to key={\${item.repoFullName}-${item.prNumber}`}` to ensure uniqueness across different repositories in the org-wide view.

  2. Display repository names in org-wide view (web/src/components/prs/prs-table.tsx, web/src/routes/prs.tsx) - Added a showRepoName prop that displays the repository name in a separate column when viewing "All projects". This makes PRs from different repos distinguishable.

  3. Added test coverage for org-wide query (tests/unit/api/routers/prs.test.ts) - Added listPRsForOrg to the mock setup and created a test case "returns PRs across all projects when no projectId given" to cover the previously untested code path.

Verification

✅ All tests passing (12/12 tests in prs.test.ts)
✅ Type checking passes
✅ Linting passes
✅ Changes committed and pushed

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Clean, well-structured PR that follows established patterns. The new PRs page mirrors the existing Work Items page across all layers (route, table component, tRPC endpoint, sidebar nav, repository). All CI checks pass. Approving with two minor suggestions.

Should Fix

  • tests/unit/api/routers/prs.test.ts:43-51mockPRSummary is missing the runCount field that was added to the PRSummary interface. The mock should include runCount: 3 (or similar) to accurately reflect the real data shape. Won't cause test failures since the test compares against its own mock, but makes the test less realistic and could mask type issues if someone copies this mock elsewhere.

  • Integration test gaplistPRsForOrg has no integration test coverage (the integration test file wasn't modified). Since the function follows the exact same pattern as the already-tested listWorkItems, this is low risk, but worth adding to tests/integration/db/prWorkItemsRepository.test.ts in a follow-up.

@aaight aaight merged commit eaa1adf into dev Mar 9, 2026
6 checks passed
@aaight
Copy link
Copy Markdown
Collaborator Author

aaight commented Mar 9, 2026

Checking the pipeline and moving the next card for the PRs page

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants