5.7 KiB
5.7 KiB
spec, created, status
| spec | created | status |
|---|---|---|
| docs/specs/ui/github-pr-review-actions.md | 2026-07-23 | completed |
Implementation Plan: GitHub PR Review Re-request
Overview
Add the missing GitHub review-request write contract, expose it beside a dismissed review, and reuse that PR detail surface on phones. Backend and core frontend work can proceed in parallel because the route and payload are fixed by the spec; mobile composition and E2E follow after the shared action works.
Backend
GitHub client contract and implementations
- Add
RequestReviewers(ctx, owner, repo, number, reviewers)toapps/backend/internal/github/client.go. - Implement GitHub REST
POST /repos/{owner}/{repo}/pulls/{number}/requested_reviewersingh_client.goandpat_client.go. - Keep
noop_client.gofail-closed. - Make
mock_client.gorecord the request and update the seeded PR'sRequestedReviewers, so integration and browser tests observe the same transition as GitHub.
Service and HTTP route
- Add a service method in
service_pr.gothat delegates the write and deletes the affectedprFeedbackCacheandprStatusCachekey after success. - Register
POST /api/v1/github/prs/:owner/:repo/:number/requested-reviewersincontroller.go. - Validate the PR number and a non-empty list of non-blank reviewer logins.
Return the established GitHub/configuration error response and
{"requested": true}on success.
Frontend
API and dismissed-review action
- Add
requestPRReviewerstoapps/web/lib/api/domains/github-api.ts. - In
pr-detail-panel.tsx, own mutation state, success/error toast, and feedback refresh using the existing approve-action pattern. - In
pr-reviews-section.tsx, reconcile review history with explicit current requests case-insensitively. Only the latestDISMISSEDreview on an open PR gets a re-request action, and a requested reviewer renders once as pending. - Add a small accessible trailing action to
pr-shared.tsxonly if needed by the existing row layout. Use a compact direct sync action on wider screens and a minimum 44px touch target on phone/coarse-pointer layouts.
Mobile design contract
- Desktop outcome: request the dismissed reviewer from the existing PR detail review row.
- Phone entry: task bottom navigation Review.
- Exemplar: GitLab's full-height mobile review in
apps/web/components/task/mobile/session-mobile-layout.tsx, plusReviewPRSelectorfor multi-PR selection. - Hierarchy/surface: optional PR selector, then one full-height PR detail surface; the dismissed-review action remains inside its review row.
- Scroll/geometry: mobile layout owns
100dvh; PR content keeps one internal vertical scroll owner; existing bottom-nav safe-area padding stays authoritative; no document horizontal overflow. - Shared logic: the same feedback hook, request handler, PR selection, and reviews component serve every viewport. Only mobile composition differs.
- Primary action: visible re-request control with an accessible reviewer name and at least a 44px active touch dimension.
Tests
- Backend transport tests assert gh/PAT method, endpoint, and reviewer JSON.
- Backend mock/service/controller tests assert mutation, validation, error behavior, and per-PR cache eviction.
- Frontend API tests assert method, path, and body.
- Review reconciliation tests cover dismissed-only eligibility, case-insensitive current requests, duplicate suppression, and closed PRs.
- Mobile layout tests cover GitHub PR Review availability and fallback to the existing GitLab surface when no GitHub PR exists.
E2E Tests
- Desktop: seed an open PR with a dismissed review, use the PR detail row action, and assert the reviewer becomes pending with no duplicate action.
- Mobile: enter Review from bottom navigation, perform the same request, and assert pending state, 44px action geometry, viewport containment, and no document horizontal overflow.
Implementation Waves
Wave 1 (parallel):
Wave 2:
Wave 3:
Review remediation (parallel):
- Task 06: PR-scoped optimistic request state — done
- Task 07: Mobile PR identity and narrow-row safety — done
- Task 08: Reviewer input hardening — done
- Task 09: Key-scoped PR cache invalidation — done
- Task 10: Persistent review-request lifecycle — done
- Task 11: Reclaim key invalidation metadata — done
Verification
After targeted task checks, run formatting before the full pipeline:
make fmt
make typecheck test lint
Then run focused production-build browser coverage:
cd apps/web
pnpm e2e:run tests/pr/pr-rerequest-review.spec.ts tests/pr/mobile-pr-rerequest-review.spec.ts
Risks
- GitHub keeps the old dismissed review in review history after a new request;
explicit
requested_reviewersmust win during rendering. - Feedback/status caches can otherwise make a successful mutation look stale.
- Adding GitHub to the phone Review destination must not remove the existing GitLab fallback for tasks without a GitHub PR.