Skip to content

Commit

Permalink
fix: Post a highlight (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
a0m0rajab committed May 29, 2023
1 parent cb53938 commit e3b7051
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 41 deletions.
12 changes: 7 additions & 5 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ export const OPEN_SAUCED_INSIGHTS_DOMAIN = "insights.opensauced.pizza";
export const AI_PR_DESCRIPTION_CONFIG_KEY = "ai-pr-description-config";

// API endpoints
export const OPEN_SAUCED_USERS_ENDPOINT = "https://api.opensauced.pizza/v1/users";
export const OPEN_SAUCED_REPOS_ENDPOINT = "https://api.opensauced.pizza/v1/repos";
export const OPEN_SAUCED_SESSION_ENDPOINT = "https://api.opensauced.pizza/v1/auth/session";
export const OPEN_SAUCED_USER_INSIGHTS_ENDPOINT = "https://api.opensauced.pizza/v1/user/insights";
export const OPEN_SAUCED_AI_PR_DESCRIPTION_ENDPOINT = "https://api.opensauced.pizza/v1/prs/description/generate";
export const OPEN_SAUCED_API_ENDPOINT = "https://api.opensauced.pizza/v1";
export const OPEN_SAUCED_USERS_ENDPOINT = `${OPEN_SAUCED_API_ENDPOINT}/users`;
export const OPEN_SAUCED_REPOS_ENDPOINT = `${OPEN_SAUCED_API_ENDPOINT}/repos`;
export const OPEN_SAUCED_SESSION_ENDPOINT = `${OPEN_SAUCED_API_ENDPOINT}/auth/session`;
export const OPEN_SAUCED_USER_INSIGHTS_ENDPOINT = `${OPEN_SAUCED_API_ENDPOINT}/user/insights`;
export const OPEN_SAUCED_AI_PR_DESCRIPTION_ENDPOINT = `${OPEN_SAUCED_API_ENDPOINT}/prs/description/generate`;
export const OPEN_SAUCED_USER_HIGHLIGHTS_ENDPOINT = `${OPEN_SAUCED_API_ENDPOINT}/user/highlights`;
export const OPEN_SAUCED_AI_CODE_REFACTOR_ENDPOINT = "https://api.opensauced.pizza/v1/prs/suggestion/generate";

// GitHub constants/selectors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,56 +23,69 @@ export const DescriptionGeneratorButton = () => {
};

const handleSubmit = async () => {
const logo = document.getElementById("ai-description-button-logo") ?? null;

try {
if (!(await isLoggedIn())) {
return window.open(SUPABASE_LOGIN_URL, "_blank");
}
const logo = document.getElementById("ai-description-button-logo");

if (!logo) {
return;
}
const url = getPullRequestAPIURL(window.location.href);
const descriptionConfig = await getAIDescriptionConfig();

if (!descriptionConfig) {
return;
}
if (!descriptionConfig.enabled) {
return alert("AI PR description is disabled!");
}
logo.classList.toggle("animate-spin");
const [diff, commitMessages] = await getDescriptionContext(url, descriptionConfig.config.source);

if (!diff && !commitMessages) {
logo.classList.toggle("animate-spin");
return alert(`No input context was generated.`);
}
if (isOutOfContextBounds([diff, commitMessages], descriptionConfig.config.maxInputLength)) {
logo.classList.toggle("animate-spin");
return alert(`Max input length exceeded. Try setting the description source to commit-messages.`);
}
const token = await getAuthToken();
const descriptionStream = await generateDescription(
token,
descriptionConfig.config.language,
descriptionConfig.config.length,
descriptionConfig.config.temperature / 10,
descriptionConfig.config.tone,
diff,
commitMessages,
);
const descriptionStream = await getAiDescription();

logo.classList.toggle("animate-spin");
if (!descriptionStream) {
return console.error("No description was generated!");
}

const textArea = document.getElementsByName(GITHUB_PR_COMMENT_TEXT_AREA_SELECTOR)[0] as HTMLTextAreaElement;

insertTextAtCursor(textArea, descriptionStream);
} catch (error: unknown) {
logo?.classList.toggle("animate-spin");

if (error instanceof Error) {
alert(error.message);
console.error("Description generation error:", error.message);
}
}
};

export const getAiDescription = async () => {
const url = getPullRequestAPIURL(window.location.href);
const descriptionConfig = await getAIDescriptionConfig();

if (!descriptionConfig) {
throw new Error("Configuration file is empty!");
}

if (!descriptionConfig.enabled) {
throw new Error("AI PR description is disabled!");
}

const [diff, commitMessages] = await getDescriptionContext(url, descriptionConfig.config.source);

if (!diff && !commitMessages) {
throw new Error(`No input context was generated.`);
}
if (isOutOfContextBounds([diff, commitMessages], descriptionConfig.config.maxInputLength)) {
throw new Error(`Max input length exceeded. Try setting the description source to commit-messages.`);
}
const token = await getAuthToken();
const descriptionStream = await generateDescription(
token,
descriptionConfig.config.language,
descriptionConfig.config.length,
descriptionConfig.config.temperature / 10,
descriptionConfig.config.tone,
diff,
commitMessages,
);

if (!descriptionStream) {
throw new Error("No description was generated!");
}

return descriptionStream;
};

25 changes: 25 additions & 0 deletions src/content-scripts/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import domUpdateWatch from "../utils/dom-utils/domUpdateWatcher";
import injectDescriptionGeneratorButton from "../utils/dom-utils/addDescriptionGenerator";
import injectChangeSuggestorButton from "../utils/dom-utils/changeSuggestorButton";
import prEditWatch, { prReviewWatch } from "../utils/dom-utils/prWatcher";
import { getAiDescription } from "./components/GenerateAIDescription/DescriptionGeneratorButton";

const processGithubPage = async () => {
if (prefersDarkMode(document.cookie)) {
Expand Down Expand Up @@ -55,3 +56,27 @@ const processGithubPage = async () => {
};

void processGithubPage();

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
switch (msg.type) {
case "get_highlight": {
const title = (document.querySelector(".js-issue-title.markdown-title") as HTMLHeadingElement)?.innerText;

sendResponse(title);
break;
}
case "get_ai_description": {
const asyncRequest = async () => {
const aiText = await getAiDescription();

sendResponse(aiText);
};

asyncRequest().catch((e: Error | undefined) => {
sendResponse(e?.toString());
console.error(e);
});
return true;
}
}
});
13 changes: 13 additions & 0 deletions src/pages/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { useOpensaucedUserCheck } from "../hooks/useOpensaucedUserCheck";
import { Profile } from "./profile";
import { goTo } from "react-chrome-extension-router";
import AIPRDescription from "./aiprdescription";
import PostOnHighlight from "./posthighlight";


import Help from "./help";

const Home = () => {
Expand Down Expand Up @@ -79,6 +82,16 @@ const Home = () => {
AI Configuration
</button>

<button
className="flex items-center bg-slate-700 hover:bg-slate-700/70 hover:text-orange text-white gap-2 p-1.5 px-3 w-full rounded-sm font-medium text-sm"
onClick={() => {
goTo(PostOnHighlight);
}}
>
<HiPencil />
Post Highlight
</button>

{currentTabIsOpensaucedUser && (
<button
className="flex items-center bg-slate-700 hover:bg-slate-700/70 hover:text-orange text-white gap-2 p-1.5 px-3 w-full rounded-sm font-medium text-sm"
Expand Down
134 changes: 134 additions & 0 deletions src/pages/posthighlight.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { useEffect, useState } from "react";
import { FaChevronLeft } from "react-icons/fa";
import OpenSaucedLogo from "../assets/opensauced-logo.svg";
import { useAuth } from "../hooks/useAuth";
import toast, { Toaster } from "react-hot-toast";
import { cerateHighlight } from "../utils/fetchOpenSaucedApiData";
import { goBack } from "react-chrome-extension-router";

const PostOnHighlight = () => {
const { authToken, user } = useAuth();
const [pageURL, setPageURL] = useState("");
const [highlightTitle, setHighlightTitle] = useState("");
const [highlightContent, setHighlightContent] = useState("");
const [isSendButtonEnabled, enableSendButton] = useState(true);

const generateAiDescription = () => {
const toastId = toast.loading("Generating summary...");

enableSendButton(false);
chrome.tabs.query({ currentWindow: true, active: true }, tabs => {
chrome.tabs.sendMessage(tabs[0].id ?? 0, { type: "get_ai_description" }, response => {
toast.dismiss(toastId);
setHighlightContent(response);
enableSendButton(true);
});
});
};


// post highlight function
const postHighlight = () => {
enableSendButton(false);
const postHighlightAPI = cerateHighlight((authToken ?? ""), pageURL, highlightTitle, highlightContent);

toast.promise(postHighlightAPI, {
loading: "Loading ...",
success: data => {
enableSendButton(true);
if (!data.ok) {
throw new Error(`Statues code ${data.status}`);
}
return (
<span>
<a
href={`https://insights.opensauced.pizza/user/${user?.user_name}/highlights`}
rel="noreferrer"
target="_blank"
>
See the highlight live
</a>
</span>
);
},
error: e => {
enableSendButton(true);
return `Uh oh, there was an error! ${e.message}`;
},
}).catch(console.error);
};

useEffect(() => {
chrome.tabs.query({ currentWindow: true, active: true }, tabs => {
setPageURL(tabs[0]?.url ?? "");
chrome.tabs.sendMessage(tabs[0].id ?? 0, { type: "get_highlight" }, setHighlightTitle);
});
}, []);

return (
<div className="p-4 bg-slate-800">
<div className="grid grid-cols-1 divide-y divider-y-center-2 min-w-[320px]">
<Toaster />

<header className="flex justify-between">
<div className="flex items-center gap-2">
<button
className="rounded-full p-2 bg-slate-700 hover:bg-slate-700/50"
onClick={() => {
goBack();
}}
>
<FaChevronLeft className="text-osOrange text-white" />
</button>

<img
alt="OpenSauced logo"
className="w-[100%]"
src={OpenSaucedLogo}
/>
</div>
</header>

<main className="text-white">

<input
className="p-1.5 rounded-md mb-2 w-full text-black"
maxLength={50}
placeholder="An amazing title here"
type="text"
value={highlightTitle}
onChange={e => setHighlightTitle(e.target.value)}
/>

<textarea
className="p-1.5 rounded-md mb-2 w-full text-black"
placeholder="Summarize this pull request"
rows={5}
value={highlightContent}
onChange={e => setHighlightContent(e.target.value)}
/>

<div className="flex justify-evenly">
<button
className="inline-block disabled:bg-gray-500 text-black bg-gh-white rounded-md p-2 text-sm font-semibold text-center select-none w-5/12 border hover:shadow-button hover:no-underline"
disabled={!isSendButtonEnabled}
onClick={() => generateAiDescription()}
>
Summarize
</button>

<button
className="inline-block disabled:bg-gray-500 text-black bg-gh-white rounded-md p-2 text-sm font-semibold text-center select-none w-5/12 border hover:shadow-button hover:no-underline"
disabled={!isSendButtonEnabled}
onClick={postHighlight}
>
Post
</button>
</div>
</main>
</div>
</div>
);
};

export default PostOnHighlight;
6 changes: 3 additions & 3 deletions src/utils/fetchGithubAPIData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ export const getPRDiff = async (url: string) => {
};

export const getPRCommitMessages = async (url: string) => {
const response = await fetch(url);
const response = await fetch(`${url}/commits`);
const data = await response.json();

if (!Array.isArray(data.commits)) {
if (!Array.isArray(data)) {
return undefined;
}
const commitMessages: string[] = (data.commits as Commit[]).map((commit: Commit): string => commit.commit.message);
const commitMessages: string[] = (data as Commit[]).map((commit: Commit): string => commit.commit.message);

return commitMessages;
};
Expand Down
16 changes: 16 additions & 0 deletions src/utils/fetchOpenSaucedApiData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
OPEN_SAUCED_SESSION_ENDPOINT,
OPEN_SAUCED_REPOS_ENDPOINT,
OPEN_SAUCED_USER_INSIGHTS_ENDPOINT,
OPEN_SAUCED_USER_HIGHLIGHTS_ENDPOINT,
} from "../constants";
import { IInsight } from "../ts/InsightDto";

Expand Down Expand Up @@ -176,3 +177,18 @@ export const updateInsight = async (userToken: string, repoId: string, checked:

return response.status === 200;
};

export const cerateHighlight = async (userToken: string, url: string, title: string, highlight: string, shipped_at?: string) => fetch(OPEN_SAUCED_USER_HIGHLIGHTS_ENDPOINT, {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `Bearer ${userToken}`,
},
method: "POST",
body: JSON.stringify({
url,
title,
shipped_at,
highlight,
}),
});

0 comments on commit e3b7051

Please sign in to comment.