diff --git a/apps/desktop/src/renderer/lib/github/openPullRequestLink/openPullRequestLink.test.ts b/apps/desktop/src/renderer/lib/github/openPullRequestLink/openPullRequestLink.test.ts index f5ed32a1601..589e9aba166 100644 --- a/apps/desktop/src/renderer/lib/github/openPullRequestLink/openPullRequestLink.test.ts +++ b/apps/desktop/src/renderer/lib/github/openPullRequestLink/openPullRequestLink.test.ts @@ -13,8 +13,8 @@ function open(url: string, action: LinkAction | null) { } describe("openPullRequestLink", () => { - it("opens a URL that is not a GitHub pull request in the browser", () => { - const url = "https://gitlab.com/acme/app/-/merge_requests/3"; + it("opens a URL that is not a pull request in the browser", () => { + const url = "https://gitlab.com/acme/app/-/issues/3"; const { openPane, openInBrowser } = open(url, "pane"); expect(openInBrowser).toHaveBeenCalledWith(url); expect(openPane).not.toHaveBeenCalled(); @@ -38,6 +38,13 @@ describe("openPullRequestLink", () => { expect(openInBrowser).not.toHaveBeenCalled(); }); + it("splits the pull request pane for a GitLab merge request", () => { + const url = "https://gitlab.com/acme/sub/app/-/merge_requests/3"; + const { openPane } = open(url, "pane"); + const ref = { repoFullName: "gitlab.com/acme/sub/app", number: 3 }; + expect(openPane).toHaveBeenCalledWith(ref, "split"); + }); + it("falls back to the split pane for an unbound tier", () => { const { openPane, openInBrowser } = open(PR_URL, null); expect(openPane).toHaveBeenCalledWith(PR_REF, "split"); diff --git a/apps/desktop/src/renderer/lib/github/pullRequestRef.ts b/apps/desktop/src/renderer/lib/github/pullRequestRef.ts index 30867d28e2f..1a0433c424d 100644 --- a/apps/desktop/src/renderer/lib/github/pullRequestRef.ts +++ b/apps/desktop/src/renderer/lib/github/pullRequestRef.ts @@ -7,8 +7,12 @@ export interface PullRequestRef { const PULL_REQUEST_URL = /^https:\/\/github\.com\/([^/?#]+\/[^/?#]+)\/pull\/(\d+)(?:[/?#]|$)/; +// A GitLab MR keeps its host in the name, so it never reads as a GitHub repo. +const MERGE_REQUEST_URL = + /^https:\/\/([^/?#]+\/[^?#]+?)\/-\/merge_requests\/(\d+)(?:[/?#]|$)/; + export function pullRequestRefFromUrl(url: string): PullRequestRef | null { - const match = PULL_REQUEST_URL.exec(url); + const match = PULL_REQUEST_URL.exec(url) ?? MERGE_REQUEST_URL.exec(url); if (!match?.[1] || !match[2]) return null; return { repoFullName: match[1], number: Number(match[2]) }; } diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/ChangesControl/components/PRStatusGroup/PRStatusGroup.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/ChangesControl/components/PRStatusGroup/PRStatusGroup.tsx index 95ee84769c9..1c5360fbe6d 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/ChangesControl/components/PRStatusGroup/PRStatusGroup.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/ChangesControl/components/PRStatusGroup/PRStatusGroup.tsx @@ -445,7 +445,7 @@ export function PRStatusGroup({ - View on GitHub + Open in browser diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/ChangesControl/components/PRStatusGroup/components/PRDetailCard/PRDetailCard.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/ChangesControl/components/PRStatusGroup/components/PRDetailCard/PRDetailCard.tsx index e010289630c..a0dff48b5ad 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/ChangesControl/components/PRStatusGroup/components/PRDetailCard/PRDetailCard.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/ChangesControl/components/PRStatusGroup/components/PRDetailCard/PRDetailCard.tsx @@ -96,7 +96,7 @@ export function PRDetailCard({ pr, checks, linkState }: PRDetailCardProps) { className="group flex items-center justify-between border-t border-border/60 px-3 py-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground" > - View on GitHub + Open in browser