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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/App.tsx
@@ -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
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
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
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
@@ -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;
@@ -1,7 +1,7 @@
import React, { useEffect, useReducer, useState } from "react";

Check warning on line 1 in src/popup/pages/aiprdescription.tsx

View workflow job for this annotation

GitHub Actions / test / Code standards

'useState' is defined but never used
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";

Check warning on line 4 in src/popup/pages/aiprdescription.tsx

View workflow job for this annotation

GitHub Actions / test / Code standards

'ImSwitch' is defined but never used
import toast, { Toaster } from "react-hot-toast";

import {
Expand All @@ -11,10 +11,9 @@
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 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 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 @@
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
@@ -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
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.
@@ -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
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
@@ -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
@@ -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
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