Skip to content

Commit

Permalink
feat: chat dialog for talking to repos (#226)
Browse files Browse the repository at this point in the history
* feat: chat dialog for talking to repos

* chat dialog start

* add spinner for indexign

* shift to react

* remove chat UI when the page is changed

* base chat layout, design and dp left

* it works!

* refactor from reviews

* add suggested queries

* embed events

* remove quotes

* tests

* handle server errors on embedding

* fix warnings

* still trying to pass these tests

* nick's suggestions
  • Loading branch information
diivi authored Aug 10, 2023
1 parent c2b41f8 commit 67f04d7
Show file tree
Hide file tree
Showing 16 changed files with 2,008 additions and 77 deletions.
1,291 changes: 1,214 additions & 77 deletions npm-shrinkwrap.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"react-dom": "^18.0.0",
"react-hot-toast": "^2.4.1",
"react-icons": "^4.8.0",
"react-markdown": "^8.0.7",
"react-syntax-highlighter": "^15.5.0",
"swiper": "^9.4.0"
},
"devDependencies": {
Expand All @@ -32,6 +34,7 @@
"@types/node-emoji": "^1.8.2",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/react-syntax-highlighter": "^15.5.7",
"@typescript-eslint/eslint-plugin": "^5.59.1",
"@vitejs/plugin-react": "^1.3.0",
"@vitest/coverage-c8": "^0.31.1",
Expand Down
10 changes: 10 additions & 0 deletions src/assets/open-sauced-orange-bg-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// OpenSauced constants
export const OPEN_SAUCED_INSIGHTS_DOMAIN = import.meta.env.VITE_OPEN_SAUCED_INSIGHTS_DOMAIN;
export const OPEN_SAUCED_API_ENDPOINT = import.meta.env.VITE_OPEN_SAUCED_API_ENDPOINT;
export const REPO_QUERY_API_ENDPOINT = "https://opensauced.tools";
export const SUPABASE_LOGIN_URL = `https://${import.meta.env.VITE_OPEN_SAUCED_SUPABASE_ID}.supabase.co/auth/v1/authorize`;

export const REPO_QUERY_EMBED_ENDPOINT = `${REPO_QUERY_API_ENDPOINT}/embed`;
export const REPO_QUERY_QUERY_ENDPOINT = `${REPO_QUERY_API_ENDPOINT}/query`;
export const REPO_QUERY_COLLECTION_ENDPOINT = `${REPO_QUERY_API_ENDPOINT}/collection`;

export const SUPABASE_AUTH_COOKIE_NAME = `sb-${import.meta.env.VITE_OPEN_SAUCED_SUPABASE_ID}-auth-token`;
export const SUPABASE_PKCE_VERIFIER_COOKIE_NAME = `sb-${import.meta.env.VITE_OPEN_SAUCED_SUPABASE_ID}-auth-token-code-verifier`;
Expand Down
21 changes: 21 additions & 0 deletions src/content-scripts/components/RepoQuery/RepoQuery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import ReactDOM from "react-dom/client";
import { RepoQuery } from "../../../repo-query/pages/main";
import { createHtmlElement } from "../../../utils/createHtmlElement";

export const RepoQueryRoot = (ownerName: string, repoName: string) => {
const repoQueryRoot = createHtmlElement("div", { id: "repo-query-root" });

ReactDOM.createRoot(repoQueryRoot).render(
<React.StrictMode>
<RepoQuery
ownerName={ownerName}
repoName={repoName}
/>
</React.StrictMode>,
);


return repoQueryRoot;
};

14 changes: 14 additions & 0 deletions src/content-scripts/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
getGithubUsername,
isGithubProfilePage,
isGithubPullRequestPage,
isGithubRepoPage,
isPullRequestCreatePage,
isPullRequestFilesChangedPage,
} from "../utils/urlMatchers";
Expand All @@ -16,6 +17,8 @@ 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 injectChatDialog from "../utils/dom-utils/addChatDialog";
import { pageUrlWatch } from "../utils/dom-utils/pageUrlWatcher";

const processGithubPage = async () => {
if (prefersDarkMode(document.cookie)) {
Expand All @@ -39,6 +42,17 @@ const processGithubPage = async () => {
} else {
injectInviteToOpenSauced(username);
}
} else if (isGithubRepoPage(window.location.href)) {
const ownerName = getGithubUsername(window.location.href) ?? "";
const repoName = window.location.href.split("/").pop() ?? "";

await injectChatDialog(ownerName, repoName);

pageUrlWatch(() => {
if (document.getElementById("repo-query-root")) {
document.getElementById("repo-query-root")?.remove();
}
}, 50);
}

/*
Expand Down
21 changes: 21 additions & 0 deletions src/repo-query/components/ChatCircle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import openSaucedLogoIcon from "../../assets/open-sauced-orange-bg-logo.svg";

export const ChatCircle = ({ toggleDialog }: { toggleDialog: () => void }) => (
<button
onClick={toggleDialog}
onKeyDown={
e => {
if (e.key === "Enter") {
toggleDialog();
}
}
}
>
<img
alt="Open Sauced Logo"
className="w-14 h-14 rounded-full fixed bottom-0 right-0 m-8 z-50 cursor-pointer"
id="chat-dialog-button-logo"
src={chrome.runtime.getURL(openSaucedLogoIcon)}
/>
</button>
);
123 changes: 123 additions & 0 deletions src/repo-query/components/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { useState } from "react";
import openSaucedLogoIcon from "../../assets/open-sauced-orange-bg-logo.svg";
import { Home } from "../pages/home";
import { IndexingPage } from "../pages/indexing";
import { Chat } from "../pages/chat";
import { RepoQueryPages } from "../../ts/types";

export const Dialog = ({ isOpen, toggleDialog, ownerName, repoName }: { isOpen: boolean, toggleDialog: () => void, ownerName: string, repoName: string }) => {
const [currentPage, setCurrentPage] = useState(RepoQueryPages.Home);

return (
<div
className="fixed bottom-20 right-0 m-8 z-50"
id="chat-dialog"
style={{ display: isOpen ? "block" : "none" }}
>
<div
className="flex flex-row justify-between items-center w-96 h-16 rounded-tl-xl rounded-tr-lg bg-slate-800 shadow-lg"
id="chat-dialog-header"
>
<div
className="flex flex-row justify-between w-full pr-4 items-center"
id="chat-dialog-header-left"
>
<div
className="flex flex-row items-center"
id="chat-dialog-header-left-logo-container"
>
<img
alt="OpenSauced logo"
className="w-12 h-12 rounded-full ml-4"
id="chat-dialog-header-left-logo"
src={`${chrome.runtime.getURL(openSaucedLogoIcon)}`}
/>

<div
className="ml-4"
id="chat-dialog-header-left-text"
>
<div
className="text-lg font-bold text-white"
id="chat-dialog-header-left-text-title"
>
OpenSauced
</div>

<div
className="text-sm text-gray-400"
id="chat-dialog-header-left-text-subtitle"
>
RepoQuery
</div>
</div>
</div>

<div
className="w-8 h-8 rounded-full bg-gray-200 flex flex-row justify-center items-center ml-4 cursor-pointer"
id="chat-dialog-header-left-close"
role="button"
tabIndex={0}
onClick={toggleDialog}
onKeyDown={
e => {
if (e.key === "Enter") {
toggleDialog();
}
}
}
>
<svg
className="w-4 h-4 text-gray-500"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 18L18 6M6 6l12 12"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
/>
</svg>
</div>
</div>
</div>

<div
className="flex flex-col w-96 h-96 rounded-bl-xl rounded-br-lg bg-white shadow-lg"
id="chat-dialog-body"
>
{
currentPage === RepoQueryPages.Home
? (
<Home
ownerName={ownerName}
repoName={repoName}
setCurrentPage={setCurrentPage}
/>
)
: currentPage === RepoQueryPages.Indexing
? (
<IndexingPage
ownerName={ownerName}
repoName={repoName}
setCurrentPage={setCurrentPage}
/>
)

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
: currentPage === RepoQueryPages.Chat
? (
<Chat
ownerName={ownerName}
repoName={repoName}
/>
)
: null
}
</div>
</div>
);
};
Loading

0 comments on commit 67f04d7

Please sign in to comment.