diff options
author | Nate Sesti <sestinj@gmail.com> | 2023-09-07 16:10:13 -0700 |
---|---|---|
committer | Nate Sesti <sestinj@gmail.com> | 2023-09-07 16:10:13 -0700 |
commit | 354a3f493074b1fb63ff4f206a94c35f05673e99 (patch) | |
tree | cb5584d95f435e4b2b87aa9aa550269f60cb28d5 /extension/react-app/src | |
parent | 5a76c61e298fc701a29807c17eaf46e1e76043bc (diff) | |
download | sncontinue-354a3f493074b1fb63ff4f206a94c35f05673e99.tar.gz sncontinue-354a3f493074b1fb63ff4f206a94c35f05673e99.tar.bz2 sncontinue-354a3f493074b1fb63ff4f206a94c35f05673e99.zip |
feat: :money_with_wings: free trial usage indicator
Diffstat (limited to 'extension/react-app/src')
-rw-r--r-- | extension/react-app/src/components/Layout.tsx | 22 | ||||
-rw-r--r-- | extension/react-app/src/components/ProgressBar.tsx | 77 | ||||
-rw-r--r-- | extension/react-app/src/pages/gui.tsx | 43 | ||||
-rw-r--r-- | extension/react-app/src/pages/settings.tsx | 9 |
4 files changed, 138 insertions, 13 deletions
diff --git a/extension/react-app/src/components/Layout.tsx b/extension/react-app/src/components/Layout.tsx index 17100c7f..6410db8a 100644 --- a/extension/react-app/src/components/Layout.tsx +++ b/extension/react-app/src/components/Layout.tsx @@ -21,8 +21,9 @@ import { Cog6ToothIcon, } from "@heroicons/react/24/outline"; import HeaderButtonWithText from "./HeaderButtonWithText"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useLocation } from "react-router-dom"; import ModelSelect from "./ModelSelect"; +import ProgressBar from "./ProgressBar"; // #region Styled Components const FOOTER_HEIGHT = "1.8em"; @@ -74,6 +75,7 @@ const GridDiv = styled.div` const Layout = () => { const navigate = useNavigate(); + const location = useLocation(); const client = useContext(GUIClientContext); const dispatch = useDispatch(); const dialogMessage = useSelector( @@ -82,10 +84,11 @@ const Layout = () => { const showDialog = useSelector( (state: RootStore) => state.uiState.showDialog ); - const dialogEntryOn = useSelector( - (state: RootStore) => state.uiState.dialogEntryOn - ); + const defaultModel = useSelector( + (state: RootStore) => + (state.serverState.config as any).models?.default?.class_name + ); // #region Selectors const bottomMessage = useSelector( @@ -175,6 +178,17 @@ const Layout = () => { )} <ModelSelect /> + {defaultModel === "MaybeProxyOpenAI" && + (location.pathname === "/settings" || + parseInt(localStorage.getItem("freeTrialCounter") || "0") >= + 125) && ( + <ProgressBar + completed={parseInt( + localStorage.getItem("freeTrialCounter") || "0" + )} + total={250} + /> + )} </div> <HeaderButtonWithText onClick={() => { diff --git a/extension/react-app/src/components/ProgressBar.tsx b/extension/react-app/src/components/ProgressBar.tsx new file mode 100644 index 00000000..b4a2efc9 --- /dev/null +++ b/extension/react-app/src/components/ProgressBar.tsx @@ -0,0 +1,77 @@ +import React from "react"; +import styled from "styled-components"; +import { StyledTooltip, lightGray, vscForeground } from "."; + +const ProgressBarWrapper = styled.div` + width: 100px; + height: 6px; + border-radius: 6px; + border: 0.5px solid ${lightGray}; + margin-top: 6px; +`; + +const ProgressBarFill = styled.div<{ completed: number; color?: string }>` + height: 100%; + background-color: ${(props) => props.color || vscForeground}; + border-radius: inherit; + transition: width 0.2s ease-in-out; + width: ${(props) => props.completed}%; +`; + +const GridDiv = styled.div` + display: grid; + grid-template-rows: 1fr auto; + align-items: center; + justify-items: center; +`; + +const P = styled.p` + margin: 0; + margin-top: 2px; + font-size: 12px; + color: ${lightGray}; + text-align: center; +`; + +interface ProgressBarProps { + completed: number; + total: number; +} + +const ProgressBar = ({ completed, total }: ProgressBarProps) => { + const fillPercentage = Math.min(100, Math.max(0, (completed / total) * 100)); + + return ( + <> + <a + href="https://continue.dev/docs/customization" + className="no-underline" + > + <GridDiv data-tooltip-id="usage_progress_bar"> + <ProgressBarWrapper> + <ProgressBarFill + completed={fillPercentage} + color={ + completed / total > 0.75 + ? completed / total > 0.95 + ? "#f00" + : "#fc0" + : undefined + } + /> + </ProgressBarWrapper> + <P> + Free Usage: {completed} / {total} + </P> + </GridDiv> + </a> + <StyledTooltip id="usage_progress_bar" place="bottom"> + { + "Continue allows you to use our OpenAI API key for up to 250 inputs. After this, you can either use your own API key, or use a local LLM. Click the progress bar to go to the docs and learn more." + } + </StyledTooltip> + </> + ); +}; + +export default ProgressBar; diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx index cb62f7ed..34e79a8f 100644 --- a/extension/react-app/src/pages/gui.tsx +++ b/extension/react-app/src/pages/gui.tsx @@ -66,6 +66,10 @@ function GUI(props: GUIProps) { // #region Selectors const history = useSelector((state: RootStore) => state.serverState.history); + const defaultModel = useSelector( + (state: RootStore) => + (state.serverState.config as any).models?.default?.class_name + ); const user_input_queue = useSelector( (state: RootStore) => state.serverState.user_input_queue ); @@ -240,6 +244,43 @@ function GUI(props: GUIProps) { return; } + // Increment localstorage counter for usage of free trial + if ( + defaultModel === "MaybeProxyOpenAI" && + (!input.startsWith("/") || input.startsWith("/edit")) + ) { + const freeTrialCounter = localStorage.getItem("freeTrialCounter"); + if (freeTrialCounter) { + const usages = parseInt(freeTrialCounter); + localStorage.setItem("freeTrialCounter", (usages + 1).toString()); + + if (usages >= 250) { + console.log("Free trial limit reached"); + dispatch(setShowDialog(true)); + dispatch( + setDialogMessage( + <div className="p-4"> + <h3>Free Trial Limit Reached</h3> + You've reached the free trial limit of 250 free inputs with + Continue's OpenAI API key. To keep using Continue, you can + either use your own API key, or use a local LLM. To read more + about the options, see our{" "} + <a href="https://continue.dev/docs/customization"> + documentation + </a> + . If you're just looking for fastest way to keep going, type + '/config' to open your Continue config file and paste your API + key into the MaybeProxyOpenAI object. + </div> + ) + ); + return; + } + } else { + localStorage.setItem("freeTrialCounter", "1"); + } + } + setWaitingForSteps(true); if ( @@ -266,7 +307,7 @@ function GUI(props: GUIProps) { client.sendMainInput(input); dispatch(temporarilyPushToUserInputQueue(input)); - // Increment localstorage counter + // Increment localstorage counter for popup const counter = localStorage.getItem("mainTextEntryCounter"); if (counter) { let currentCount = parseInt(counter); diff --git a/extension/react-app/src/pages/settings.tsx b/extension/react-app/src/pages/settings.tsx index 9a3d3cc2..8b3d9c5b 100644 --- a/extension/react-app/src/pages/settings.tsx +++ b/extension/react-app/src/pages/settings.tsx @@ -4,19 +4,12 @@ import { useSelector } from "react-redux"; import { RootStore } from "../redux/store"; import { useNavigate } from "react-router-dom"; import { ContinueConfig } from "../../../schema/ContinueConfig"; -import { - Button, - Select, - TextArea, - lightGray, - secondaryDark, -} from "../components"; +import { Button, TextArea, lightGray, secondaryDark } from "../components"; import styled from "styled-components"; import { ArrowLeftIcon } from "@heroicons/react/24/outline"; import Loader from "../components/Loader"; import InfoHover from "../components/InfoHover"; import { FormProvider, useForm } from "react-hook-form"; -import ModelSettings from "../components/ModelSettings"; const Hr = styled.hr` border: 0.5px solid ${lightGray}; |