d6bb9ac6ec00fdc4da4c116a7db8bdf0562ff6b6
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8e55c3c477 |
feat(web): surface PR merge-conflict & mergeability state in the CI popover (#1448)
* feat(web): surface PR mergeability + conflict state in the CI popover The CI hover popover showed checks/reviews but nothing about mergeability, so an unmergeable PR silently dropped its merge button with no reason. Add a mergeability row that reuses the detail panel's conflict banner + "Resolve conflicts" agent prompt for dirty PRs, a "Behind base" chip, and a branch-protection note explaining why a blocked PR is gated. Replace the compact merge split-button+dropdown with an inline primary + "or <method>" buttons so the menu's detached portal no longer closes the hover popover. * feat(web): reflect PR mergeability in status colors and badges The PR status pill, badge, and chat-input CI chip derived their colour from checks/reviews only, so a conflicted or blocked PR still read as a green "all good" check. Map dirty -> red, behind -> amber, and branch-protection blocked -> amber across getPRStatusColor, the PRStatusIcon badge, and the chip glyph, so the indicators agree with the popover. Blocked stays sky/in-progress while a requested review is still outstanding (that's the awaiting-review gate, not a hard block). * refactor(web): remove dead merge-menu keep-open plumbing The compact merge control was redesigned to inline buttons (no dropdown portal), which already fixes the hover popover closing. That leaves the keepOpen ref / setKeepOpen / onMergeMenuOpenChange / onMenuOpenChange chain threaded through usePopoverInteractions, PRCIPopover, and PRMergeButton unreachable: the popover always renders PRMergeButton with compact, and the only DropdownMenu lives in the non-compact detail-panel path that never passes the callback. Drop the unused scaffolding (flagged by OpenCode + greptile). * fix(web): keep CI popover quiet for blocked PRs only awaiting review PRMergeabilityRow rendered "Blocked by branch protection" for any blocked PR, including one blocked solely because a requested reviewer hasn't responded. That contradicted the chip/pill/badge, which deliberately read that case as the calm "awaiting review" state. Skip the note (render nothing) when isPRAwaitingReview is true, and narrow blockedReason so an empty checks_state no longer falsely claims a required status check failed. Flagged by Claude (blocker) and greptile. * refactor(web): rename mergeability-notice compact prop to popover The `compact` prop made the chip/text larger (to match the popover's text-xs rows) while ConflictBanner's `compact` tightened padding — so "compact" rendered bigger, which reads as inverted. Rename it to `popover` (the variant rendered inside the CI hover popover) and document that the chip intentionally matches the popover rows. No visual change. Flagged by cubic. * fix(web): show default cursor on disabled compact merge alternates The compact "or <method>" alternates kept cursor-pointer while disabled (during the ~1s merging state); add disabled:cursor-default to match the primary button. Flagged by OpenCode. |
||
|
|
b8a09bc5ea |
fix(github): pick allowed merge method so squash-only repos stop 405ing (#999)
* fix(github): pick allowed merge method so squash-only repos stop 405ing The merge button sent an empty merge_method to GitHub, which defaults to "merge" regardless of repo settings — squash-only / rebase-only repos returned 405 "Merge commits are not allowed on this repository". The backend now resolves an empty method to the first allowed one via a new GetRepoMergeMethods endpoint (5-min cache), and the frontend renders a GitHub-style split button so users can pick among the allowed methods. * fix(github): address PR #999 review feedback - pr-merge-button: extract repo-methods fetch to useRepoMergeMethods hook (Claude bot); hide button while methods are loading so the primary label doesn't flicker (Claude bot); drop e.preventDefault on dropdown items so Radix closes the menu on selection (Greptile P1). - gh_client / pat_client: treat missing allow_* fields as false instead of true so a permission-gated response can't pick a disallowed merge method (cubic P2). - service.MergePR: only overwrite mergeMethod when pickDefaultMergeMethod returns non-empty, so a degenerate all-false config falls through to GitHub's default with the real error (Claude bot). * fix(github): don't hide merge button on lookup failure Round-2 PR feedback (Claude, Greptile, CodeRabbit, cubic): the `if (!methods) return null` guard added in the previous round to avoid label flicker turned a transient repo-methods lookup failure into a permanent UI lockout — the button would stay hidden until unmount/remount. - pr-merge-button: revert the null-guard; treat null as "use backend resolver", render the plain primary button without a dropdown. - use-repo-merge-methods: add a 5-min frontend TTL to match the backend cache so admin merge-strategy flips are visible without a page reload. Catch block now triggers a rerender, and co-waiting consumers attach both fulfilled/rejected handlers to avoid silent rejection swallowing. * test(github): cover useRepoMergeMethods + silence rejection warning Round-3 PR feedback (Claude): - Swallow rejections in the originating fetch chain instead of rethrowing, so the first consumer's promise never escapes the hook as an unhandled rejection. Coalesced consumers already re-render to null, which is the same state a fresh "not loaded" call would show. - Add use-repo-merge-methods.test.ts covering: null-on-missing-params, loading then resolution, cache hit on remount, concurrent-fetch coalescing, retry-on-failure (no cache poisoning, no unhandled rejection), and TTL-expiry refetch via fake timers. * test(github): cover httpGetRepoMergeMethods error branches Round-4 PR feedback (Claude): the new endpoint had only happy-path coverage. Add tests matching httpMergePR's existing shape: - nil client → 503 (ErrNoClient) - GitHubAPIError{404} → 404 - generic upstream error → 500 --------- Co-authored-by: Kandev Agent <agent@kandev.dev> |
||
|
|
3d860290da |
feat(github): add merge button when PR is ready to merge (#979)
* feat(github): add merge button when PR is ready to merge Surfaces a one-click merge action in the PR detail panel header and as a compact green pill in the PR topbar hover popover, gated by the existing isPRReadyToMerge predicate (open, CI success, mergeable_state=clean, and either approved or no review process). Backend adds MergePR to the Client interface, implements it across PAT/gh/Noop/Mock clients, exposes PUT /api/v1/github/prs/:owner/:repo/:number/merge, and maps GitHub 405/409 to HTTP 409 so the UI can show a clear error. * fix(github): address PR review feedback on merge endpoint - Map gh CLI 404/403/405/409 stderr to *GitHubAPIError via a new ghMergeStatusCode helper, so merge conflicts surface as HTTP 409 for gh CLI users (previously only PAT users got the right status). - Service.MergePR returns ErrNoClient when unconfigured; httpMergePR translates that to HTTP 503 with github_not_configured, matching httpListRepoBranches. - httpMergePR distinguishes empty body (io.EOF, fall through to default merge method) from malformed JSON (HTTP 400 invalid payload). - PRMergeButton tracks a local merged flag so the button stays hidden across the async refresh window after a successful merge. * test(github): cover merge helpers and extract PRMergeButton - TestGhMergeStatusCode locks in the gh CLI stderr → status-code parser for nil, unrelated errors, the HTTP / status: / bare-phrase forms of 404/403/405/409, and a 500 non-match guard. - Broaden ghMergeStatusCode to also match "405 Method Not Allowed" / "409 Conflict" phrase forms so the merge endpoint's 409 mapping does not depend on the gh CLI keeping its current "HTTP <code>" prefix. - TestHttpMergePR_MalformedJSON covers the new non-EOF bind-error branch (truncated body → 400). TestHttpMergePR_NoClient_Returns503 covers the ErrNoClient → 503 path on Service.MergePR. - Document the post/put error-type divergence on PATClient.post so a future caller does not silently lose per-status mapping. - Move PRMergeButton out of pr-shared.tsx into its own file, and reset the local "merged" flag when taskPR.id changes so an instance that re-renders for a different PR does not stay hidden. --------- Co-authored-by: Kandev Agent <agent@kandev.dev> |