feat(forge): Pull Requests sidebar section + branch fork icon#5
Conversation
- Backend `list_prs` (gh/glab CLI) returns normalized open PRs/MRs: number, title, url, source branch, draft, author (+avatar), rolled-up CI status, and review decision. GitHub is fully rich; GitLab is degraded (no CI/review/avatar from `glab mr list`). New `open_url` command opens a PR in the browser (guarded to http/https). - Sidebar "Pull Requests" section: rich rows (author avatar, #number, CI dot, review mark, title, draft tag). Click opens in browser; right-click copies the URL. Manual refresh button (a network CLI call, off the hot path). - Graph: a branch badge whose branch has an open PR/MR shows the fork icon instead of the monitor; its right-click menu gains "Open pull request #N". Fetched on repo load / provider change + manual refresh only, never after every git op. Non-forge remotes yield an empty list (section just shows empty).
|
Warning Review limit reached
Next review available in: 51 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughAdds pull/merge request listing support: a Rust ChangesPR/MR listing feature
Estimated code review effort: 3 (Moderate) | ~30 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant Sidebar
participant RepoView
participant TauriBackend as Tauri Backend
participant ForgeCLI as gh/glab CLI
User->>Sidebar: Click "Refresh pull requests"
Sidebar->>RepoView: onRefreshPrs()
RepoView->>TauriBackend: listPrs(repo)
TauriBackend->>ForgeCLI: run gh pr list / glab mr list
ForgeCLI-->>TauriBackend: JSON PR/MR data
TauriBackend-->>RepoView: PullRequest[]
RepoView->>Sidebar: prs, prByBranch, prBranchSet
Sidebar-->>User: Render PR rows with status
User->>Sidebar: Click PR row
Sidebar->>RepoView: onOpenPr(url)
RepoView->>TauriBackend: openUrl(url)
TauriBackend-->>User: Open URL in browser
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src-tauri/src/git/forge.rs`:
- Around line 143-171: The PR/MR listing helpers are silently truncating results
because `list_github` hard-caps `gh pr list` at 50 and the GitLab counterpart
uses default CLI paging, so the sidebar can miss items. Update `list_github` and
the GitLab list function to fetch all pages/results (use explicit pagination or
loop until exhausted) instead of relying on fixed defaults, and keep the
existing `PullRequest` mapping intact while aggregating every page into the
returned vector.
- Around line 143-150: The PR refresh path can hang because list_github and
list_gitlab rely on run_cli, which currently uses Command::output() without any
timeout. Update run_cli to enforce a bounded execution time and make sure both
list_github and list_gitlab surface a timeout error instead of waiting
indefinitely. Use the existing run_cli symbol as the central fix point so repo
load and provider changes cannot stall the sidebar refresh.
In `@src/components/RepoView.tsx`:
- Around line 242-252: `refreshPrs` currently swallows failures and can apply
stale responses because it lacks the same request-lifecycle protection used
elsewhere in `RepoView.tsx`. Update `refreshPrs` to use a request guard or
`alive`/request-id check like `refreshStats` and the avatar effects so older
in-flight `api.listPrs(path)` results cannot overwrite newer ones, and stop
using `.catch(() => {})`; instead surface errors through the existing
notification flow, similar to `refreshWipsManually`. Keep the manual
`onRefreshPrs={refreshPrs}` wiring, but route it through a notifying wrapper if
needed so both the mount/provider-change path and the sidebar refresh action
report success/failure consistently.
In `@src/components/Sidebar.tsx`:
- Around line 235-273: The PR row in Sidebar.tsx uses a clickable div with
onClick and onContextMenu but lacks keyboard accessibility and an explicit role.
Update the PR row markup (the branch-row pr element in the PR list render) to
match the accessible pattern used by the branch/tag rows elsewhere in
Sidebar.tsx by adding an appropriate role, keyboard handlers for Enter/Space
activation, and any needed tab focus support so the row is operable by keyboard
and announced correctly by assistive tech.
- Around line 159-174: The refresh button in Sidebar should explicitly set
type="button" so it does not default to submit if rendered inside a form. Update
the button in prActions to include the type attribute alongside the existing
onClick handler and RefreshIcon, keeping the current stopPropagation and
onRefreshPrs behavior unchanged.
- Line 232: The Pull Requests section hides the manual refresh action when prs
is empty, which blocks discovering newly opened PRs from an empty state. In
Sidebar.tsx, update the Group usage for the Pull Requests section so actions
does not depend on prs.length and always exposes prActions; keep the conditional
only if some specific action truly must be hidden, not the refresh control.
Reference the Sidebar component and the prs/prActions wiring to make the refresh
button available even when there are zero pull requests.
In `@src/styles.css`:
- Around line 732-734: The `.pr-ci-pending` style is using a hardcoded hex color
instead of a theme-aware CSS variable, unlike `.pr-ci-success` and
`.pr-ci-failure`. Update the `.pr-ci-pending` rule in `src/styles.css` to use an
existing CSS custom property if available, or add a new variable alongside the
other CI status colors and reference it here so the pending state matches
light/dark theme variants consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: c1d7bc67-09ad-470d-8750-e046ecef83c5
📒 Files selected for processing (10)
src-tauri/src/git/forge.rssrc-tauri/src/lib.rssrc/api.tssrc/components/GraphView.tsxsrc/components/RepoView.tsxsrc/components/Sidebar.tsxsrc/icons.tsxsrc/storage.tssrc/styles.csssrc/types.ts
| fn list_github(dir: &Path) -> AppResult<Vec<PullRequest>> { | ||
| let out = run_cli( | ||
| dir, | ||
| &[ | ||
| "gh", "pr", "list", "--state", "open", "--limit", "50", "--json", | ||
| "number,title,url,headRefName,isDraft,author,statusCheckRollup,reviewDecision", | ||
| ], | ||
| )?; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map relevant files and inspect the CLI wrapper plus call sites.
git ls-files | rg '(^|/)src-tauri/src/git/|(^|/)src-tauri/src/.*run_cli|(^|/)src-tauri/src/.*cli|(^|/)src-tauri/src/.*provider'
rg -n "fn run_cli|run_cli\(|list_github\(|list_gitlab\(|refreshPrs\(" src-tauri/src -S
# Read the likely implementation slices.
for f in \
src-tauri/src/git/forge.rs \
src-tauri/src/git/mod.rs \
src-tauri/src/git/*.rs
do
[ -f "$f" ] || continue
echo "===== $f ====="
wc -l "$f"
done
sed -n '1,240p' src-tauri/src/git/forge.rsRepository: jcardonne/gitchef
Length of output: 11061
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== forge.rs around list_gitlab ==="
sed -n '240,316p' src-tauri/src/git/forge.rs
echo "=== list_prs callers / refreshPrs ==="
rg -n "list_prs\(|refreshPrs|provider change|repo load|load repo|open.*repo|auto.*prs|prs" src-tauri/src -S
echo "=== other run_cli wrappers ==="
rg -n "Command::new\(.*output\(|Command::new|timeout|kill\(" src-tauri/src -SRepository: jcardonne/gitchef
Length of output: 12686
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== frontend PR refresh flow ==="
rg -n "refreshPrs|list_prs|provider change|repo load|loadRepo|openRepo|selectedRepo|remote provider|GitHub|GitLab" . -S
echo "=== files that mention PR sidebar state ==="
rg -n "PR sidebar|pull request|merge request|prs" src* . -g '!target' -g '!node_modules' -S
echo "=== search for timeout/cancellation around invoke calls ==="
rg -n "AbortController|timeout|setTimeout|clearTimeout|cancel.*invoke|invoke\(" . -SRepository: jcardonne/gitchef
Length of output: 16938
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== RepoView PR refresh handler ==="
sed -n '230,270p' src/components/RepoView.tsx
echo "=== Tauri list_prs command ==="
sed -n '140,160p' src-tauri/src/lib.rs
echo "=== forge.rs run_cli and list_prs ==="
sed -n '1,170p' src-tauri/src/git/forge.rsRepository: jcardonne/gitchef
Length of output: 9019
Add a timeout around the PR CLI calls run_cli() still uses Command::output() with no timeout, and both list_github() and list_gitlab() are invoked automatically on repo load/provider change. If gh/glab hangs on auth or a dead network, the PR refresh never settles and the sidebar stays stale.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src-tauri/src/git/forge.rs` around lines 143 - 150, The PR refresh path can
hang because list_github and list_gitlab rely on run_cli, which currently uses
Command::output() without any timeout. Update run_cli to enforce a bounded
execution time and make sure both list_github and list_gitlab surface a timeout
error instead of waiting indefinitely. Use the existing run_cli symbol as the
central fix point so repo load and provider changes cannot stall the sidebar
refresh.
| fn list_github(dir: &Path) -> AppResult<Vec<PullRequest>> { | ||
| let out = run_cli( | ||
| dir, | ||
| &[ | ||
| "gh", "pr", "list", "--state", "open", "--limit", "50", "--json", | ||
| "number,title,url,headRefName,isDraft,author,statusCheckRollup,reviewDecision", | ||
| ], | ||
| )?; | ||
| let prs: Vec<GhPr> = serde_json::from_str(&out) | ||
| .map_err(|e| AppError::Msg(format!("could not parse `gh pr list` output: {e}")))?; | ||
| Ok(prs | ||
| .into_iter() | ||
| .map(|p| { | ||
| let author_avatar = (!p.login().is_empty()) | ||
| .then(|| format!("https://github.com/{}.png?size=40", p.author.login)); | ||
| PullRequest { | ||
| number: p.number, | ||
| title: p.title, | ||
| url: p.url, | ||
| branch: p.head_ref_name, | ||
| draft: p.is_draft, | ||
| author: p.author.login.clone(), | ||
| author_avatar, | ||
| checks: rollup_checks(&p.status_check_rollup), | ||
| review: normalize_review(p.review_decision.as_deref()), | ||
| } | ||
| }) | ||
| .collect()) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
Silent truncation of PR/MR lists.
gh pr list is capped at --limit 50, and glab mr list uses no --per-page/--page flag, so it defaults to GitLab CLI's built-in page size of 30. Repos with more open PRs/MRs than these caps will silently show an incomplete sidebar list with no indication more exist.
♻️ Proposed fix
let out = run_cli(dir, &["glab", "mr", "list", "--output", "json"])?;
+ // Without --per-page, glab defaults to 30 results per page.- let out = run_cli(dir, &["glab", "mr", "list", "--output", "json"])?;
+ let out = run_cli(dir, &["glab", "mr", "list", "--output", "json", "--per-page", "50"])?;Also applies to: 240-258
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src-tauri/src/git/forge.rs` around lines 143 - 171, The PR/MR listing helpers
are silently truncating results because `list_github` hard-caps `gh pr list` at
50 and the GitLab counterpart uses default CLI paging, so the sidebar can miss
items. Update `list_github` and the GitLab list function to fetch all
pages/results (use explicit pagination or loop until exhausted) instead of
relying on fixed defaults, and keep the existing `PullRequest` mapping intact
while aggregating every page into the returned vector.
| // Open PRs/MRs for the sidebar section + the badge fork-icon. A network CLI hit, | ||
| // so it's OFF the hot refresh() path: fetched on load / provider change and via | ||
| // the section's manual refresh, never after every git op. Non-forge repo -> []. | ||
| const refreshPrs = useCallback(() => { | ||
| if (repo?.provider !== "github" && repo?.provider !== "gitlab") { | ||
| setPrs([]); | ||
| return; | ||
| } | ||
| api.listPrs(path).then(setPrs).catch(() => {}); | ||
| }, [path, repo?.provider]); | ||
| useEffect(() => refreshPrs(), [refreshPrs]); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
refreshPrs swallows errors and lacks a stale-response guard.
refreshPrs doubles as the mount/provider-change effect handler and the manual "refresh" action wired at Line 1680 (onRefreshPrs={refreshPrs}), but:
- It has no id/
aliveguard like the file's other async fetches (refreshStats'sstatsReq,commitReq,fileReq, or the avatar effects'aliveflag), so an in-flight request from mount/provider-change can resolve after a newer manual-refresh request and silently overwrite it with stale data. - Failures are swallowed via
.catch(() => {}). The sibling manual-refresh action,refreshWipsManually, notifies on both success and failure — clicking "refresh PRs" whengh/glabfails (not authenticated, CLI missing, rate-limited) gives the user no feedback at all.
🛡️ Proposed fix: add a request guard and a notifying manual-refresh wrapper
+ const prsReq = useRef(0);
const refreshPrs = useCallback(() => {
if (repo?.provider !== "github" && repo?.provider !== "gitlab") {
setPrs([]);
- return;
+ return Promise.resolve();
}
- api.listPrs(path).then(setPrs).catch(() => {});
+ const id = ++prsReq.current;
+ return api.listPrs(path).then((list) => {
+ if (prsReq.current === id) setPrs(list);
+ });
}, [path, repo?.provider]);
- useEffect(() => refreshPrs(), [refreshPrs]);
+ useEffect(() => {
+ refreshPrs().catch(() => {});
+ }, [refreshPrs]);
+ const refreshPrsManually = () =>
+ refreshPrs()
+ .then(() => notify("Refreshed pull requests"))
+ .catch((e) => notify(String(e), true));And at Line 1680:
- onRefreshPrs={refreshPrs}
+ onRefreshPrs={refreshPrsManually}Also applies to: 1674-1680
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/RepoView.tsx` around lines 242 - 252, `refreshPrs` currently
swallows failures and can apply stale responses because it lacks the same
request-lifecycle protection used elsewhere in `RepoView.tsx`. Update
`refreshPrs` to use a request guard or `alive`/request-id check like
`refreshStats` and the avatar effects so older in-flight `api.listPrs(path)`
results cannot overwrite newer ones, and stop using `.catch(() => {})`; instead
surface errors through the existing notification flow, similar to
`refreshWipsManually`. Keep the manual `onRefreshPrs={refreshPrs}` wiring, but
route it through a notifying wrapper if needed so both the mount/provider-change
path and the sidebar refresh action report success/failure consistently.
| // Hover-revealed "refresh pull requests" button (a network CLI call, on demand). | ||
| const prActions = ( | ||
| <span className="group-actions"> | ||
| <button | ||
| className="group-action" | ||
| title="Refresh pull requests" | ||
| onClick={(e) => { | ||
| e.stopPropagation(); | ||
| onRefreshPrs(); | ||
| }} | ||
| > | ||
| <RefreshIcon /> | ||
| </button> | ||
| </span> | ||
| ); | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Add explicit type="button" to the refresh button.
Static analysis flags this: a <button> with no type defaults to submit, which can trigger accidental form submission if this component is ever nested in a <form>.
🔧 Proposed fix
<button
className="group-action"
title="Refresh pull requests"
+ type="button"
onClick={(e) => {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Hover-revealed "refresh pull requests" button (a network CLI call, on demand). | |
| const prActions = ( | |
| <span className="group-actions"> | |
| <button | |
| className="group-action" | |
| title="Refresh pull requests" | |
| onClick={(e) => { | |
| e.stopPropagation(); | |
| onRefreshPrs(); | |
| }} | |
| > | |
| <RefreshIcon /> | |
| </button> | |
| </span> | |
| ); | |
| // Hover-revealed "refresh pull requests" button (a network CLI call, on demand). | |
| const prActions = ( | |
| <span className="group-actions"> | |
| <button | |
| className="group-action" | |
| title="Refresh pull requests" | |
| type="button" | |
| onClick={(e) => { | |
| e.stopPropagation(); | |
| onRefreshPrs(); | |
| }} | |
| > | |
| <RefreshIcon /> | |
| </button> | |
| </span> | |
| ); |
🧰 Tools
🪛 React Doctor (0.5.8)
[warning] 162-162: Your users can submit the form by accident because a <button> with no type defaults to submit.
Set an explicit button type so plain buttons do not submit forms by accident: type="button", "submit", or "reset".
(button-has-type)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/Sidebar.tsx` around lines 159 - 174, The refresh button in
Sidebar should explicitly set type="button" so it does not default to submit if
rendered inside a form. Update the button in prActions to include the type
attribute alongside the existing onClick handler and RefreshIcon, keeping the
current stopPropagation and onRefreshPrs behavior unchanged.
Source: Linters/SAST tools
| ))} | ||
| </Group> | ||
|
|
||
| <Group title="Pull Requests" icon={<PullRequestIcon />} count={prs.length} open={open.pullRequests} onToggle={() => toggle("pullRequests")} actions={prs.length ? prActions : undefined}> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Refresh action is hidden exactly when it's most needed.
actions={prs.length ? prActions : undefined} disables the manual refresh button when prs is empty. Since PR fetching only happens on load, provider change, or this manual refresh (per PR objectives, not the regular refresh() path), this button is the only way to discover a newly-opened PR when the section currently shows zero PRs — but it's unavailable in exactly that state.
🐛 Proposed fix
- <Group title="Pull Requests" icon={<PullRequestIcon />} count={prs.length} open={open.pullRequests} onToggle={() => toggle("pullRequests")} actions={prs.length ? prActions : undefined}>
+ <Group title="Pull Requests" icon={<PullRequestIcon />} count={prs.length} open={open.pullRequests} onToggle={() => toggle("pullRequests")} actions={prActions}>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Group title="Pull Requests" icon={<PullRequestIcon />} count={prs.length} open={open.pullRequests} onToggle={() => toggle("pullRequests")} actions={prs.length ? prActions : undefined}> | |
| <Group title="Pull Requests" icon={<PullRequestIcon />} count={prs.length} open={open.pullRequests} onToggle={() => toggle("pullRequests")} actions={prActions}> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/Sidebar.tsx` at line 232, The Pull Requests section hides the
manual refresh action when prs is empty, which blocks discovering newly opened
PRs from an empty state. In Sidebar.tsx, update the Group usage for the Pull
Requests section so actions does not depend on prs.length and always exposes
prActions; keep the conditional only if some specific action truly must be
hidden, not the refresh control. Reference the Sidebar component and the
prs/prActions wiring to make the refresh button available even when there are
zero pull requests.
| <div | ||
| key={pr.number} | ||
| className="branch-row pr" | ||
| title={`#${pr.number} ${pr.title}\n${pr.branch} · @${pr.author}`} | ||
| onClick={() => onOpenPr(pr.url)} | ||
| onContextMenu={(e) => { | ||
| e.preventDefault(); | ||
| onPrMenu(pr); | ||
| }} | ||
| > | ||
| {pr.author_avatar ? ( | ||
| <img className="pr-avatar" src={pr.author_avatar} alt="" /> | ||
| ) : ( | ||
| <span className="pr-avatar pr-avatar-fallback" aria-hidden="true"> | ||
| {pr.author.charAt(0).toUpperCase() || "?"} | ||
| </span> | ||
| )} | ||
| <span className="pr-num">#{pr.number}</span> | ||
| {pr.checks !== "none" && ( | ||
| <span className={`pr-ci pr-ci-${pr.checks}`} title={`CI: ${pr.checks}`} /> | ||
| )} | ||
| {pr.review === "approved" && ( | ||
| <span className="pr-review approved" title="Approved"> | ||
| <CheckIcon size={11} /> | ||
| </span> | ||
| )} | ||
| {pr.review === "changes_requested" && ( | ||
| <span className="pr-review changes" title="Changes requested"> | ||
| <CloseIcon size={11} /> | ||
| </span> | ||
| )} | ||
| <span className="branch-name pr-title">{pr.title}</span> | ||
| {pr.draft && ( | ||
| <span className="sm-badge" title="Draft"> | ||
| draft | ||
| </span> | ||
| )} | ||
| </div> | ||
| ))} |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
PR row click handler lacks keyboard support/role.
Static analysis flags the clickable PR row div: no onKeyDown/onKeyUp pairing with onClick, and no role for screen readers. This mirrors the existing branch/tag row pattern elsewhere in the file, so it's not a regression specific to this change, but worth fixing alongside if accessibility is a goal.
🧰 Tools
🪛 React Doctor (0.5.8)
[warning] 235-235: Keyboard users can't trigger this click handler because there's no keyboard one, so add onKeyUp, onKeyDown, or onKeyPress.
Pair onClick with a key handler so keyboard users can trigger it.
(click-events-have-key-events)
[warning] 235-235: Screen reader users can't tell this click handler is interactive because it has no role, so add a role or use a button or link.
Give clickable static elements a role, or use a button or link.
(no-static-element-interactions)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/Sidebar.tsx` around lines 235 - 273, The PR row in Sidebar.tsx
uses a clickable div with onClick and onContextMenu but lacks keyboard
accessibility and an explicit role. Update the PR row markup (the branch-row pr
element in the PR list render) to match the accessible pattern used by the
branch/tag rows elsewhere in Sidebar.tsx by adding an appropriate role, keyboard
handlers for Enter/Space activation, and any needed tab focus support so the row
is operable by keyboard and announced correctly by assistive tech.
Source: Linters/SAST tools
| .pr-ci-pending { | ||
| background: #e0af68; | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Hardcoded color breaks theme consistency.
.pr-ci-pending uses a literal #e0af68 while .pr-ci-success/.pr-ci-failure use var(--add)/var(--del). This won't adapt to light/dark theme variants the way the other two do.
♻️ Suggested fix (add a CSS variable if one doesn't already exist)
.pr-ci-pending {
- background: `#e0af68`;
+ background: var(--pending, `#e0af68`);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .pr-ci-pending { | |
| background: #e0af68; | |
| } | |
| .pr-ci-pending { | |
| background: var(--pending, `#e0af68`); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/styles.css` around lines 732 - 734, The `.pr-ci-pending` style is using a
hardcoded hex color instead of a theme-aware CSS variable, unlike
`.pr-ci-success` and `.pr-ci-failure`. Update the `.pr-ci-pending` rule in
`src/styles.css` to use an existing CSS custom property if available, or add a
new variable alongside the other CI status colors and reference it here so the
pending state matches light/dark theme variants consistently.
The hasPr icon condition also required a local branch ref, so a PR branch that isn't checked out locally (shown as origin/x only) rendered the cloud instead of the fork. Drop that requirement - any PR-matched branch shows the single fork.
|
🎉 This PR is included in version 0.27.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
Adds pull/merge request awareness to the app.
forge::list_prsviagh/glabCLI (normalized struct),open_urlcommand (http/https-guarded).Notes
glab mr listJSON lacks CI-rollup / review-decision / avatar, so those show none/initials for GitLab. Title/number/branch/draft/author still work.refresh()path (it's a network CLI call).Test
cargo test(newrollup_checks+normalize_reviewtests; 64 pass). Verifiedgh pr list --jsonshape against a live repo matches the serde structs.tscclean,vitest56/56,vite buildok.Summary by CodeRabbit
New Features
Bug Fixes
httpandhttpsURLs only.