diff options
Diffstat (limited to 'extension/react-app/src/components')
-rw-r--r-- | extension/react-app/src/components/DebugPanel.tsx | 99 | ||||
-rw-r--r-- | extension/react-app/src/components/Layout.tsx | 210 |
2 files changed, 210 insertions, 99 deletions
diff --git a/extension/react-app/src/components/DebugPanel.tsx b/extension/react-app/src/components/DebugPanel.tsx deleted file mode 100644 index fffb6c6e..00000000 --- a/extension/react-app/src/components/DebugPanel.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import React, { useEffect, useState } from "react"; -import styled from "styled-components"; -import { postVscMessage } from "../vscode"; -import { useDispatch } from "react-redux"; -import { - setApiUrl, - setVscMachineId, - setSessionId, - setVscMediaUrl, - setDataSwitchOn, -} from "../redux/slices/configSlice"; -import { setHighlightedCode } from "../redux/slices/miscSlice"; -import { updateFileSystem } from "../redux/slices/debugContexSlice"; -import { defaultBorderRadius, secondaryDark, vscBackground } from "."; -interface DebugPanelProps { - tabs: { - element: React.ReactElement; - title: string; - }[]; -} - -const TabBar = styled.div<{ numTabs: number }>` - display: grid; - grid-template-columns: repeat(${(props) => props.numTabs}, 1fr); -`; - -const TabsAndBodyDiv = styled.div` - height: 100%; - border-radius: ${defaultBorderRadius}; - scrollbar-base-color: transparent; -`; - -function DebugPanel(props: DebugPanelProps) { - const dispatch = useDispatch(); - useEffect(() => { - const eventListener = (event: any) => { - switch (event.data.type) { - case "onLoad": - dispatch(setApiUrl(event.data.apiUrl)); - dispatch(setVscMachineId(event.data.vscMachineId)); - dispatch(setSessionId(event.data.sessionId)); - dispatch(setVscMediaUrl(event.data.vscMediaUrl)); - dispatch(setDataSwitchOn(event.data.dataSwitchOn)); - break; - case "highlightedCode": - dispatch(setHighlightedCode(event.data.rangeInFile)); - dispatch(updateFileSystem(event.data.filesystem)); - break; - } - }; - window.addEventListener("message", eventListener); - postVscMessage("onLoad", {}); - return () => window.removeEventListener("message", eventListener); - }, []); - - const [currentTab, setCurrentTab] = useState(0); - - return ( - <TabsAndBodyDiv> - {props.tabs.length > 1 && ( - <TabBar numTabs={props.tabs.length}> - {props.tabs.map((tab, index) => { - return ( - <div - key={index} - className={`p-2 cursor-pointer text-center ${ - index === currentTab - ? "bg-secondary-dark" - : "bg-vsc-background" - }`} - onClick={() => setCurrentTab(index)} - > - {tab.title} - </div> - ); - })} - </TabBar> - )} - {props.tabs.map((tab, index) => { - return ( - <div - key={index} - hidden={index !== currentTab} - style={{ - scrollbarGutter: "stable both-edges", - minHeight: "100%", - display: "grid", - gridTemplateRows: "1fr auto", - }} - > - {tab.element} - </div> - ); - })} - </TabsAndBodyDiv> - ); -} - -export default DebugPanel; diff --git a/extension/react-app/src/components/Layout.tsx b/extension/react-app/src/components/Layout.tsx new file mode 100644 index 00000000..30cb5df2 --- /dev/null +++ b/extension/react-app/src/components/Layout.tsx @@ -0,0 +1,210 @@ +import styled from "styled-components"; +import { defaultBorderRadius, secondaryDark, vscForeground } from "."; +import { Outlet } from "react-router-dom"; +import Onboarding from "./Onboarding"; +import TextDialog from "./TextDialog"; +import { useContext } from "react"; +import { GUIClientContext } from "../App"; +import { useDispatch, useSelector } from "react-redux"; +import { RootStore } from "../redux/store"; +import { + setBottomMessage, + setBottomMessageCloseTimeout, + setDialogEntryOn, + setDialogMessage, + setShowDialog, +} from "../redux/slices/uiStateSlice"; +import { + PlusIcon, + FolderIcon, + BookOpenIcon, + ChatBubbleOvalLeftEllipsisIcon, +} from "@heroicons/react/24/outline"; +import HeaderButtonWithText from "./HeaderButtonWithText"; +import { useNavigate } from "react-router-dom"; + +// #region Styled Components + +const LayoutTopDiv = styled.div` + height: 100%; + border-radius: ${defaultBorderRadius}; + scrollbar-base-color: transparent; + scrollbar-width: thin; +`; + +const BottomMessageDiv = styled.div<{ displayOnBottom: boolean }>` + position: fixed; + bottom: ${(props) => (props.displayOnBottom ? "50px" : undefined)}; + top: ${(props) => (props.displayOnBottom ? undefined : "50px")}; + left: 0; + right: 0; + margin: 8px; + margin-top: 0; + background-color: ${secondaryDark}; + color: ${vscForeground}; + border-radius: ${defaultBorderRadius}; + padding: 12px; + z-index: 100; + box-shadow: 0px 0px 2px 0px ${vscForeground}; + max-height: 50vh; + overflow: scroll; +`; + +const Footer = styled.footer` + display: flex; + flex-direction: row; + gap: 8px; + justify-content: right; + padding: 8px; + align-items: center; + margin-top: 8px; + border-top: 0.1px solid gray; +`; + +// #endregion + +const Layout = () => { + const navigate = useNavigate(); + const client = useContext(GUIClientContext); + const dispatch = useDispatch(); + const { showDialog, dialogEntryOn, dialogMessage } = useSelector( + (state: RootStore) => state.uiState + ); + + // #region Selectors + const vscMediaUrl = useSelector( + (state: RootStore) => state.config.vscMediaUrl + ); + + const { bottomMessage, displayBottomMessageOnBottom } = useSelector( + (state: RootStore) => state.uiState + ); + + // #endregion + + return ( + <LayoutTopDiv> + <div + style={{ + scrollbarGutter: "stable both-edges", + minHeight: "100%", + display: "grid", + gridTemplateRows: "1fr auto", + }} + > + <Onboarding /> + <TextDialog + showDialog={showDialog} + onEnter={(text) => { + client?.sendMainInput(`/feedback ${text}`); + dispatch(setShowDialog(false)); + }} + onClose={() => { + dispatch(setShowDialog(false)); + }} + message={dialogMessage} + entryOn={dialogEntryOn} + /> + <Outlet /> + + <BottomMessageDiv + displayOnBottom={displayBottomMessageOnBottom} + onMouseEnter={() => { + dispatch(setBottomMessageCloseTimeout(undefined)); + }} + onMouseLeave={(e) => { + if (!e.buttons) { + dispatch(setBottomMessage(undefined)); + } + }} + hidden={!bottomMessage} + > + {bottomMessage} + </BottomMessageDiv> + <Footer> + {vscMediaUrl && ( + <a + href="https://github.com/continuedev/continue" + style={{ marginRight: "auto" }} + > + <img + src={`${vscMediaUrl}/continue-dev-square.png`} + width="22px" + style={{ backgroundColor: "black", color: "red" }} + /> + </a> + )} + <HeaderButtonWithText + onClick={() => { + // Show the dialog + dispatch( + setDialogMessage(`Continue uses GPT-4 by default, but works with any model. If you'd like to keep your code completely private, there are few options: + + Run a local model with ggml: [5 minute quickstart](https://github.com/continuedev/ggml-server-example) + + Use Azure OpenAI service, which is GDPR and HIPAA compliant: [Tutorial](https://continue.dev/docs/customization#azure-openai-service) + + If you already have an LLM deployed on your own infrastructure, or would like to do so, please contact us at hi@continue.dev. + `) + ); + dispatch(setDialogEntryOn(false)); + dispatch(setShowDialog(true)); + }} + text={"Use Private Model"} + > + <div + style={{ + fontSize: "18px", + marginLeft: "2px", + marginRight: "2px", + }} + > + 🔒 + </div> + </HeaderButtonWithText> + <HeaderButtonWithText + onClick={() => { + client?.loadSession(undefined); + }} + text="New Session" + > + <PlusIcon width="1.4em" height="1.4em" /> + </HeaderButtonWithText> + <HeaderButtonWithText + onClick={() => { + navigate("/history"); + }} + text="History" + > + <FolderIcon width="1.4em" height="1.4em" /> + </HeaderButtonWithText> + <a + href="https://continue.dev/docs/how-to-use-continue" + className="no-underline" + > + <HeaderButtonWithText text="Docs"> + <BookOpenIcon width="1.4em" height="1.4em" /> + </HeaderButtonWithText> + </a> + <HeaderButtonWithText + onClick={() => { + // Set dialog open + dispatch( + setDialogMessage( + "Having trouble using Continue? Want a new feature? Let us know! This box is anonymous, but we will promptly address your feedback." + ) + ); + dispatch(setDialogEntryOn(true)); + dispatch(setShowDialog(true)); + }} + text="Feedback" + > + <ChatBubbleOvalLeftEllipsisIcon width="1.4em" height="1.4em" /> + </HeaderButtonWithText> + </Footer> + </div> + </LayoutTopDiv> + ); +}; + +export default Layout; |