summaryrefslogtreecommitdiff
path: root/extension/react-app/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'extension/react-app/src/components')
-rw-r--r--extension/react-app/src/components/DebugPanel.tsx99
-rw-r--r--extension/react-app/src/components/Layout.tsx210
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;