Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: extension settings #132

Merged
merged 11 commits into from
Jun 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect } from "react";
import Start from "./pages/start";
import Home from "./pages/home";
import Loading from "./pages/loading";
import Start from "./popup/pages/start";
import Home from "./popup/pages/home";
import Loading from "./popup/pages/loading";
import { useAuth } from "./hooks/useAuth";
import { goTo } from "react-chrome-extension-router";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ const handleSubmit = async (commentNode: HTMLElement) => {
if (!descriptionConfig) {
return;
}
if (!descriptionConfig.enabled) {
return alert("AI PR description is disabled!");
}

logo.classList.toggle("animate-spin");
button.classList.toggle("pointer-events-none");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const DescriptionGeneratorButton = () => {
</span>
<tool-tip for="ai-description-gen">Generate PR description</tool-tip>`,
onclick: handleSubmit,

});

return descriptionGeneratorButton;
Expand All @@ -34,6 +33,13 @@ const handleSubmit = async () => {
if (!logo || !button) {
return;
}

const descriptionConfig = await getAIDescriptionConfig();

if (!descriptionConfig) {
return;
}

logo.classList.toggle("animate-spin");
button.classList.toggle("pointer-events-none");

Expand Down
2 changes: 1 addition & 1 deletion src/content-scripts/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const processGithubPage = async () => {
} else if (isPullRequestFilesChangedPage(window.location.href)) {
prReviewWatch(injectChangeSuggestorButton, 500);
} else if (isGithubPullRequestPage(window.location.href)) {
prEditWatch(injectDescriptionGeneratorButton);
prEditWatch(injectDescriptionGeneratorButton, 500);
void injectAddPRToHighlightsButton();
} else if (isGithubProfilePage(window.location.href)) {
const username = getGithubUsername(window.location.href);
Expand Down
55 changes: 55 additions & 0 deletions src/popup/components/ToggleSwitch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useState } from "react";

const Toggle = ({ settingName, settingLabel, enabledSetting }: { settingName: string; enabledSetting: boolean; settingLabel: string }) => {
const [enabled, setEnabled] = useState(enabledSetting);

const changeSetting = async (value: boolean) => {
const settingsConfig = await chrome.storage.sync.get("osSettingsConfig");

if (settingsConfig.osSettingsConfig === undefined) {
const defaultSettings = { aiPrDescription: false };

await chrome.storage.sync.set({ osSettingsConfig: defaultSettings });
}

const newSettingsConfig = { ...settingsConfig.osSettingsConfig, [settingName]: value };

await chrome.storage.sync.set({ osSettingsConfig: newSettingsConfig });

setEnabled(value);
};

return (
<div className="flex items-center justify-between mt-3">
<span className="text-sm font-medium text-gray-400">
{settingLabel}
</span>

<label className="inline-flex relative items-center mr-5 cursor-pointer">
<input
readOnly
checked={enabled}
className="sr-only peer"
type="checkbox"
/>

<div
aria-checked="false"
className="w-11 h-6 bg-gray-200 rounded-full peer peer-focus:ring-green-300 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-green-600"
role="checkbox"
tabIndex={0}
onClick={ async () => {
enabled ? await changeSetting(false) : await changeSetting(true);
}}
onKeyDown={ async e => {
if (e.key === "Enter") {
enabled ? await changeSetting(false) : await changeSetting(true);
}
}}
/>
</label>
</div>
);
};

export default Toggle;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect, useReducer, useState } from "react";
import { FaChevronLeft } from "react-icons/fa";
import OpenSaucedLogo from "../assets/opensauced-logo.svg";
import OpenSaucedLogo from "../../assets/opensauced-logo.svg";
import { ImSwitch } from "react-icons/im";
import toast, { Toaster } from "react-hot-toast";

Expand All @@ -11,10 +11,9 @@ import {
DescriptionLanguage,
setAIDescriptionConfig,
getDefaultDescriptionConfig,
toggleAIPRDescriptionEnabled,
} from "../utils/aiprdescription/descriptionconfig";
import { useRefs } from "../hooks/useRefs";
import { configurationReducer } from "../utils/aiprdescription/configurationReducer";
} from "../../utils/aiprdescription/descriptionconfig";
import { useRefs } from "../../hooks/useRefs";
import { configurationReducer } from "../../utils/aiprdescription/configurationReducer";
import { goBack } from "react-chrome-extension-router";

const AIPRDescription = () => {
Expand All @@ -24,15 +23,13 @@ const AIPRDescription = () => {
const tones: DescriptionTone[] = ["exciting", "persuasive", "informative", "humorous", "formal"];
const sources: DescriptionSource[] = ["diff", "commitMessage", "both"];
const languages: DescriptionLanguage[] = ["english", "spanish", "french", "german", "italian", "portuguese", "dutch", "russian", "chinese", "korean"];
const [formDisabled, setFormDisabled] = useState<boolean>(true);


useEffect(() => {
const descriptionConfig = async () => {
const configData = await getAIDescriptionConfig();

dispatch({ type: "SET", value: configData });
setFormDisabled(!configData?.enabled);
};

void descriptionConfig();
Expand All @@ -47,10 +44,7 @@ const AIPRDescription = () => {
const source = (refs.source as HTMLSelectElement).value as DescriptionSource;
const tone = (refs.tone as HTMLSelectElement).value as DescriptionTone;

void setAIDescriptionConfig({
enabled: true,
config: { length, temperature, maxInputLength, language, source, tone },
});
void setAIDescriptionConfig({ config: { length, temperature, maxInputLength, language, source, tone } });
toast.success("Configuration updated!");
};

Expand Down Expand Up @@ -78,32 +72,14 @@ const AIPRDescription = () => {
src={OpenSaucedLogo}
/>
</div>

<button
title="Toggle AI PR Description"
className={`text-lg ${formDisabled ? "text-gray-400" : "text-orange"
}`}
onClick={() => {
setFormDisabled(!formDisabled);
dispatch({ type: "TOGGLE_ENABLED", value: config });
void toggleAIPRDescriptionEnabled();
if (formDisabled) {
toast.success("AI PR Description enabled!");
} else {
toast.error("AI PR Description disabled!");
}
}}
>
<ImSwitch />
</button>
</header>

<main className="text-white">
<form
ref={setRefFromKey("form")}
onSubmit={handleFormSubmit}
>
<fieldset disabled={formDisabled}>
<fieldset>
<h1 className="text-2xl text-white font-bold my-2">
OpenSauced AI
</h1>
Expand Down
6 changes: 3 additions & 3 deletions src/pages/help.tsx → src/popup/pages/help.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { FaChevronLeft } from "react-icons/fa";
import OpenSaucedLogo from "../assets/opensauced-logo.svg";
import { EXTERNAL_RESOURCES } from "../constants";
import OpenSaucedLogo from "../../assets/opensauced-logo.svg";
import { EXTERNAL_RESOURCES } from "../../constants";
import {
HiOutlineBookOpen,
HiOutlineChatBubbleLeftRight,
} from "react-icons/hi2";
import { goBack } from "react-chrome-extension-router";
import { VscIssues } from "react-icons/vsc";
import { version } from "../../package.json";
import { version } from "../../../package.json";

const Help = () => (
<div className="p-4 bg-slate-800">
Expand Down
28 changes: 20 additions & 8 deletions src/pages/home.tsx → src/popup/pages/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,22 @@ import {
HiPencil,
HiUserCircle,
} from "react-icons/hi2";
import { useEffect, useState } from "react";
import OpenSaucedLogo from "../assets/opensauced-logo.svg";
import { useAuth } from "../hooks/useAuth";
import { useOpensaucedUserCheck } from "../hooks/useOpensaucedUserCheck";
import { FiSettings } from "react-icons/fi";
import OpenSaucedLogo from "../../assets/opensauced-logo.svg";
import { useAuth } from "../../hooks/useAuth";
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 { getHighlights } from "../utils/fetchOpenSaucedApiData";
import { getHighlights } from "../../utils/fetchOpenSaucedApiData";

import Help from "./help";
import { OPEN_SAUCED_INSIGHTS_DOMAIN } from "../constants";
import type { Highlight } from "../ts/types";
import { useIsGithubPRPageCheck } from "../hooks/useGithubPRPageCheck";
import { useEffect, useState } from "react";
import Settings from "./settings";
import { OPEN_SAUCED_INSIGHTS_DOMAIN } from "../../constants";
import type { Highlight } from "../../ts/types";
import { useIsGithubPRPageCheck } from "../../hooks/useGithubPRPageCheck";

const Home = () => {
const { user } = useAuth();
Expand Down Expand Up @@ -215,6 +217,16 @@ const Home = () => {
<HiOutlineQuestionMarkCircle />
Help
</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-fit rounded-sm font-medium text-sm"
onClick={() => {
goTo(Settings);
}}
>
<FiSettings />
Settings
</button>
</footer>
</div>
</div>
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useEffect, useState } from "react";
import { FaChevronLeft } from "react-icons/fa";
import OpenSaucedLogo from "../assets/opensauced-logo.svg";
import { useAuth } from "../hooks/useAuth";
import OpenSaucedLogo from "../../assets/opensauced-logo.svg";
import { useAuth } from "../../hooks/useAuth";
import toast, { Toaster } from "react-hot-toast";
import { createHighlight } from "../../utils/fetchOpenSaucedApiData";
import { goBack } from "react-chrome-extension-router";
import { OPEN_SAUCED_INSIGHTS_DOMAIN } from "../constants";
import { getAiDescription } from "../content-scripts/components/GenerateAIDescription/DescriptionGeneratorButton";
import { createHighlight } from "../utils/fetchOpenSaucedApiData";
import { OPEN_SAUCED_INSIGHTS_DOMAIN } from "../../constants";
import { getAiDescription } from "../../content-scripts/components/GenerateAIDescription/DescriptionGeneratorButton";

const PostOnHighlight = ({ prUrl, prTitle }: { prUrl: string, prTitle: string }) => {
const { authToken, user } = useAuth();
Expand Down
12 changes: 6 additions & 6 deletions src/pages/profile.tsx → src/popup/pages/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import { FaBrain, FaChevronLeft, FaRobot } from "react-icons/fa";
import { RiLinkedinFill, RiLinkM, RiTwitterFill } from "react-icons/ri";
import { SiC, SiCplusplus, SiCsharp, SiGoland, SiJavascript, SiPhp, SiPython, SiReact, SiRuby, SiRust, SiTypescript } from "react-icons/si";
import { DiJava } from "react-icons/di";
import OpenSaucedLogo from "../assets/opensauced-logo.svg";
import { getUserData, getUserPRData, getUserHighlightsData } from "../utils/fetchOpenSaucedApiData";
import OpenSaucedLogo from "../../assets/opensauced-logo.svg";
import { getUserData, getUserPRData, getUserHighlightsData } from "../../utils/fetchOpenSaucedApiData";
import { emojify } from "node-emoji";
import { goBack, goTo } from "react-chrome-extension-router";
import { getRelativeDays } from "../utils/dateUtils";
import { getUserPRVelocity } from "../utils/getUserPRVelocity";
import { getRelativeDays } from "../../utils/dateUtils";
import { getUserPRVelocity } from "../../utils/getUserPRVelocity";
import { BiExit } from "react-icons/bi";
import Start from "./start";
import { optLogOut } from "../utils/checkAuthentication";
import { OPEN_SAUCED_INSIGHTS_DOMAIN } from "../constants";
import { optLogOut } from "../../utils/checkAuthentication";
import { OPEN_SAUCED_INSIGHTS_DOMAIN } from "../../constants";

const interestIcon = {
python: <SiPython />,
Expand Down
78 changes: 78 additions & 0 deletions src/popup/pages/settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { FaChevronLeft } from "react-icons/fa";
import OpenSaucedLogo from "../../assets/opensauced-logo.svg";
import { goBack } from "react-chrome-extension-router";
import Toggle from "../components/ToggleSwitch";
import { useEffect, useState } from "react";

export type SettingsConfig = Record<string, boolean | undefined>;

const settingLabels: Record<string, string> = {
aiPrDescription: "AI PR Description",
codeRefactor: "Code Refactor",
};

const Settings = () => {
const [settingsConfig, setSettingsConfig] = useState<SettingsConfig>({});

useEffect(() => {
const getSettingsDataFromStorage = async () => {
const settingsConfig = await chrome.storage.sync.get("osSettingsConfig");

if (settingsConfig.osSettingsConfig === undefined) {
const defaultSettings = { aiPrDescription: true, codeRefactor: true };

await chrome.storage.sync.set({ osSettingsConfig: defaultSettings });
setSettingsConfig(defaultSettings);
} else {
setSettingsConfig(settingsConfig.osSettingsConfig);
}
};

void getSettingsDataFromStorage();
}, []);

return (
<div className="p-4 bg-slate-800">
<div className="grid grid-cols-1 divide-y divide-white/40 divider-y-center-2 min-w-[320px] text-white">
<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="main-content text-white">
<h3 className="text font-medium text-base leading-10">Settings:</h3>

{
Object.keys(settingsConfig).map(settingName => (
<Toggle
key={settingName}
enabledSetting={settingsConfig[settingName]!}
settingLabel={settingLabels[settingName]}
settingName={settingName}
/>
))

}

<div className="flex flex-col gap-2" />
</main>
</div>
</div>
);
};

export default Settings;
4 changes: 2 additions & 2 deletions src/pages/start.tsx → src/popup/pages/start.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import OpenSaucedLogo from "../assets/opensauced-logo.svg";
import { optLogIn } from "../utils/checkAuthentication";
import OpenSaucedLogo from "../../assets/opensauced-logo.svg";
import { optLogIn } from "../../utils/checkAuthentication";

const Start = () => (
<div className="p-4 bg-slate-800">
Expand Down
3 changes: 0 additions & 3 deletions src/utils/aiprdescription/configurationReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ export const configurationReducer = (state: DescriptionConfig, action: { type: s
case "SET_TONE":
newState.config.tone = action.value;
break;
case "TOGGLE_ENABLED":
newState.enabled = !newState.enabled;
break;
case "CLEAR":
newState = getDefaultDescriptionConfig();
break;
Expand Down
Loading