mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 19:43:15 +00:00
feat: add OpenPR button for GitHub pull request creation (#132)
* Apply patch * Apply patch * Apply patch * Apply patch * Apply patch * improve colors and icons * drop log * cr
This commit is contained in:
parent
4c29af3849
commit
4fbd1f4861
3 changed files with 124 additions and 0 deletions
80
apps/web/src/components/github/open-pr-button.tsx
Normal file
80
apps/web/src/components/github/open-pr-button.tsx
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
"use client";
|
||||
|
||||
import { useStreamContext } from "@/providers/Stream";
|
||||
import { TooltipIconButton } from "@/components/ui/tooltip-icon-button";
|
||||
import { useQueryState } from "nuqs";
|
||||
import {
|
||||
GitPullRequest,
|
||||
GitMerge,
|
||||
GitPullRequestClosed,
|
||||
GitPullRequestDraft,
|
||||
} from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { getPullRequest } from "@/utils/github";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export function OpenPRButton() {
|
||||
const stream = useStreamContext();
|
||||
const [branch] = useQueryState("branch");
|
||||
const [prState, setPrState] = useState<
|
||||
"open" | "closed" | "draft" | "merged"
|
||||
>();
|
||||
const [pullRequest, setPullRequest] = useState<Record<string, any>>();
|
||||
|
||||
useEffect(() => {
|
||||
const baseBranch =
|
||||
stream.values.targetRepository?.branch ??
|
||||
stream.values.targetRepository?.baseCommit ??
|
||||
branch;
|
||||
if (
|
||||
!stream.values.branchName ||
|
||||
!stream.values.targetRepository ||
|
||||
!baseBranch
|
||||
) {
|
||||
return;
|
||||
}
|
||||
getPullRequest({
|
||||
owner: stream.values.targetRepository.owner,
|
||||
repo: stream.values.targetRepository.repo,
|
||||
baseBranch: baseBranch,
|
||||
headBranch: stream.values.branchName,
|
||||
}).then((pr) => {
|
||||
if (!pr) return;
|
||||
setPullRequest(pr);
|
||||
if (pr.merged_at) {
|
||||
setPrState("merged");
|
||||
} else if (pr.draft) {
|
||||
setPrState("draft");
|
||||
} else {
|
||||
setPrState(pr.state);
|
||||
}
|
||||
});
|
||||
}, [stream.values?.branchName, stream.values.targetRepository, branch]);
|
||||
|
||||
if (!pullRequest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleOpenPR = () => {
|
||||
window.open(pullRequest.html_url, "_blank", "noopener,noreferrer");
|
||||
};
|
||||
|
||||
return (
|
||||
<TooltipIconButton
|
||||
tooltip={`Open Pull Request #${pullRequest.number}`}
|
||||
variant="ghost"
|
||||
onClick={handleOpenPR}
|
||||
className={cn({
|
||||
"text-green-500 hover:text-green-600": prState === "open",
|
||||
"text-red-500 hover:text-red-600": prState === "closed",
|
||||
"text-gray-500 hover:text-gray-600": prState === "draft",
|
||||
"text-[#8957e5] hover:text-[#7847d1]": prState === "merged",
|
||||
})}
|
||||
>
|
||||
{prState === "merged" && <GitMerge className="size-4" />}
|
||||
{prState === "draft" && <GitPullRequestDraft className="size-4" />}
|
||||
{prState === "closed" && <GitPullRequestClosed className="size-4" />}
|
||||
{prState === "open" && <GitPullRequest className="size-4" />}
|
||||
</TooltipIconButton>
|
||||
);
|
||||
}
|
||||
|
|
@ -45,6 +45,7 @@ import { ConfigurationSidebar } from "../configuration-sidebar";
|
|||
import { DEFAULT_CONFIG_KEY, useConfigStore } from "@/hooks/useConfigStore";
|
||||
import { RepositoryBranchSelectors } from "../github/repo-branch-selectors";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { OpenPRButton } from "../github/open-pr-button";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
|
|
@ -115,6 +116,7 @@ export function Thread() {
|
|||
"chatHistoryOpen",
|
||||
parseAsBoolean.withDefault(false),
|
||||
);
|
||||
const [baseBranch, setBaseBranch] = useQueryState("base-branch");
|
||||
|
||||
const [configSidebarOpen, setConfigSidebarOpen] = useState(false);
|
||||
|
||||
|
|
@ -446,6 +448,7 @@ export function Thread() {
|
|||
|
||||
<div className="col-span-2 flex items-center justify-end gap-2 text-gray-700">
|
||||
<GitHubOAuthButton />
|
||||
<OpenPRButton />
|
||||
<TooltipIconButton
|
||||
tooltip="Configuration"
|
||||
variant="ghost"
|
||||
|
|
|
|||
|
|
@ -238,3 +238,44 @@ export interface Branch {
|
|||
};
|
||||
protected: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a pull request for a specific repository using OAuth access token
|
||||
*/
|
||||
export async function getPullRequest(inputs: {
|
||||
owner: string;
|
||||
repo: string;
|
||||
baseBranch: string;
|
||||
headBranch: string;
|
||||
}) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${getBaseApiUrl()}github/proxy/repos/${inputs.owner}/${inputs.repo}/pulls?base=${inputs.baseBranch}&head=${inputs.headBranch}`,
|
||||
{
|
||||
headers: {
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
"User-Agent": "OpenSWE-Agent",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(
|
||||
`Failed to fetch pull request: ${JSON.stringify(errorData)}`,
|
||||
);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (data && Array.isArray(data) && data.length > 0) {
|
||||
return data.filter((d) => d.head?.ref === inputs.headBranch)[0];
|
||||
}
|
||||
return data?.[0];
|
||||
} catch (e) {
|
||||
console.error("Failed to get pull request", {
|
||||
inputs,
|
||||
error: e,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue