diff options
Diffstat (limited to 'extension/react-app/src')
| -rw-r--r-- | extension/react-app/src/App.tsx | 13 | ||||
| -rw-r--r-- | extension/react-app/src/pages/gui.tsx (renamed from extension/react-app/src/tabs/gui.tsx) | 0 | ||||
| -rw-r--r-- | extension/react-app/src/tabs/additionalContext.tsx | 18 | ||||
| -rw-r--r-- | extension/react-app/src/tabs/chat/MessageDiv.tsx | 75 | ||||
| -rw-r--r-- | extension/react-app/src/tabs/chat/index.tsx | 267 | ||||
| -rw-r--r-- | extension/react-app/src/tabs/main.tsx | 189 | ||||
| -rw-r--r-- | extension/react-app/src/tabs/welcome.tsx | 22 | 
7 files changed, 2 insertions, 582 deletions
| diff --git a/extension/react-app/src/App.tsx b/extension/react-app/src/App.tsx index 8785f88f..c9bd42e0 100644 --- a/extension/react-app/src/App.tsx +++ b/extension/react-app/src/App.tsx @@ -1,8 +1,5 @@  import DebugPanel from "./components/DebugPanel"; -import MainTab from "./tabs/main"; -import WelcomeTab from "./tabs/welcome"; -import ChatTab from "./tabs/chat"; -import GUI from "./tabs/gui"; +import GUI from "./pages/gui";  import { createContext } from "react";  import useContinueGUIProtocol from "./hooks/useWebsocket";  import ContinueGUIClientProtocol from "./hooks/useContinueGUIProtocol"; @@ -18,13 +15,7 @@ function App() {      <GUIClientContext.Provider value={client}>        <DebugPanel          tabs={[ -          { -            element: <GUI />, -            title: "GUI", -          }, -          // { element: <MainTab />, title: "Debug Panel" }, -          // { element: <WelcomeTab />, title: "Welcome" }, -          // { element: <ChatTab />, title: "Chat" }, +          { element: <GUI />, title: "GUI" }          ]}        />      </GUIClientContext.Provider> diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/pages/gui.tsx index b6a18dc8..b6a18dc8 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/pages/gui.tsx diff --git a/extension/react-app/src/tabs/additionalContext.tsx b/extension/react-app/src/tabs/additionalContext.tsx deleted file mode 100644 index 98fce9f1..00000000 --- a/extension/react-app/src/tabs/additionalContext.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; -import { H3, TextArea } from "../components"; - -function AdditionalContextTab() { -  return ( -    <div className="mx-5"> -      <H3>Additional Context</H3> -      <TextArea -        rows={8} -        placeholder="Copy and paste information related to the bug from GitHub Issues, Slack threads, or other notes here." -        className="additionalContextTextarea" -      ></TextArea> -      <br></br> -    </div> -  ); -} - -export default AdditionalContextTab; diff --git a/extension/react-app/src/tabs/chat/MessageDiv.tsx b/extension/react-app/src/tabs/chat/MessageDiv.tsx deleted file mode 100644 index 3543dd93..00000000 --- a/extension/react-app/src/tabs/chat/MessageDiv.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React, { useEffect } from "react"; -import { ChatMessage } from "../../redux/store"; -import styled from "styled-components"; -import { -  buttonColor, -  defaultBorderRadius, -  secondaryDark, -} from "../../components"; -import VSCodeFileLink from "../../components/VSCodeFileLink"; -import ReactMarkdown from "react-markdown"; -import "../../highlight/dark.min.css"; -import hljs from "highlight.js"; -import { useSelector } from "react-redux"; -import { selectIsStreaming } from "../../redux/selectors/chatSelectors"; - -const Container = styled.div` -  padding-left: 8px; -  padding-right: 8px; -  border-radius: 8px; -  margin: 3px; -  width: fit-content; -  max-width: 75%; -  overflow-y: scroll; -  word-wrap: break-word; -  -ms-word-wrap: break-word; -  height: fit-content; -  overflow: hidden; -  background-color: ${(props) => { -    if (props.role === "user") { -      return buttonColor; -    } else { -      return secondaryDark; -    } -  }}; -  float: ${(props) => { -    if (props.role === "user") { -      return "right"; -    } else { -      return "left"; -    } -  }}; -  display: block; - -  & pre { -    border: 1px solid gray; -    border-radius: ${defaultBorderRadius}; -  } -`; - -function MessageDiv(props: ChatMessage) { -  const [richContent, setRichContent] = React.useState<JSX.Element[]>([]); -  const isStreaming = useSelector(selectIsStreaming); - -  useEffect(() => { -    if (!isStreaming) { -      hljs.highlightAll(); -    } -  }, [richContent, isStreaming]); - -  useEffect(() => { -    setRichContent([ -      <ReactMarkdown key={1} children={props.content}></ReactMarkdown>, -    ]); -  }, [props.content]); - -  return ( -    <> -      <div className="overflow-auto"> -        <Container role={props.role}>{richContent}</Container> -      </div> -    </> -  ); -} - -export default MessageDiv; diff --git a/extension/react-app/src/tabs/chat/index.tsx b/extension/react-app/src/tabs/chat/index.tsx deleted file mode 100644 index a93ad4f9..00000000 --- a/extension/react-app/src/tabs/chat/index.tsx +++ /dev/null @@ -1,267 +0,0 @@ -import React, { useCallback, useEffect, useRef, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { selectChatMessages } from "../../redux/selectors/chatSelectors"; -import MessageDiv from "./MessageDiv"; -import styled from "styled-components"; -import { addMessage, setIsStreaming } from "../../redux/slices/chatSlice"; -import { AnyAction, Dispatch } from "@reduxjs/toolkit"; -import { closeStream, streamUpdate } from "../../redux/slices/chatSlice"; -import { ChatMessage, RootStore } from "../../redux/store"; -import { postVscMessage, vscRequest } from "../../vscode"; -import { defaultBorderRadius, Loader } from "../../components"; -import { selectHighlightedCode } from "../../redux/selectors/miscSelectors"; -import { readRangeInVirtualFileSystem } from "../../util"; -import { selectDebugContext } from "../../redux/selectors/debugContextSelectors"; - -let textEntryBarHeight = "30px"; - -const ChatContainer = styled.div` -  display: grid; -  grid-template-rows: 1fr auto; -  height: 100%; -`; - -const BottomDiv = styled.div` -  display: grid; -  grid-template-rows: auto auto; -`; - -const BottomButton = styled.button( -  (props: { active: boolean }) => ` -  font-size: 10px; -  border: none; -  color: white; -  margin-right: 4px; -  cursor: pointer; -  background-color: ${props.active ? "black" : "gray"}; -  border-radius: ${defaultBorderRadius}; -  padding: 8px; -` -); - -const TextEntryBar = styled.input` -  height: ${textEntryBarHeight}; -  border-bottom-left-radius: ${defaultBorderRadius}; -  border-bottom-right-radius: ${defaultBorderRadius}; -  padding: 8px; -  border: 1px solid white; -  background-color: black; -  color: white; -  outline: none; -`; - -function ChatTab() { -  const dispatch = useDispatch(); -  const chatMessages = useSelector(selectChatMessages); -  const isStreaming = useSelector((state: RootStore) => state.chat.isStreaming); -  const baseUrl = useSelector((state: RootStore) => state.config.apiUrl); -  const debugContext = useSelector(selectDebugContext); - -  const [includeHighlightedCode, setIncludeHighlightedCode] = useState(true); -  const [writeToEditor, setWriteToEditor] = useState(false); -  const [waitingForResponse, setWaitingForResponse] = useState(false); - -  const highlightedCode = useSelector(selectHighlightedCode); - -  const streamToStateThunk = useCallback( -    (dispatch: Dispatch<AnyAction>, getResponse: () => Promise<Response>) => { -      let streamToCursor = writeToEditor; -      getResponse().then((resp) => { -        setWaitingForResponse(false); -        if (resp.body) { -          resp.body.pipeTo( -            new WritableStream({ -              write(chunk) { -                let update = new TextDecoder("utf-8").decode(chunk); -                dispatch(streamUpdate(update)); -                if (streamToCursor) { -                  postVscMessage("streamUpdate", { update }); -                } -              }, -              close() { -                dispatch(closeStream()); -                if (streamToCursor) { -                  postVscMessage("closeStream", null); -                } -              }, -            }) -          ); -        } -      }); -    }, -    [writeToEditor] -  ); - -  const compileHiddenChatMessages = useCallback(async () => { -    let messages: ChatMessage[] = []; -    if ( -      includeHighlightedCode && -      highlightedCode?.filepath !== undefined && -      highlightedCode?.range !== undefined && -      debugContext.filesystem[highlightedCode.filepath] !== undefined -    ) { -      let fileContents = readRangeInVirtualFileSystem( -        highlightedCode, -        debugContext.filesystem -      ); -      if (fileContents) { -        messages.push({ -          role: "user", -          content: fileContents, -        }); -      } -    } else { -      // Similarity search over workspace -      let data = await vscRequest("queryEmbeddings", { -        query: chatMessages[chatMessages.length - 1].content, -      }); -      let codeContextMessages = data.results.map( -        (result: { id: string; document: string }) => { -          let msg: ChatMessage = { -            role: "user", -            content: `File: ${result.id} \n ${result.document}`, -          }; -          return msg; -        } -      ); -      codeContextMessages.push({ -        role: "user", -        content: -          "Use the above code to help you answer the question below. Answer in asterisk bullet points, and give the full path whenever you reference files.", -      }); -      messages.push(...codeContextMessages); -    } - -    let systemMsgContent = writeToEditor -      ? "Respond only with the exact code requested, no additional text." -      : "Use the above code to help you answer the question below. Respond in markdown if using bullets or other special formatting, being sure to specify language for code blocks."; - -    messages.push({ -      role: "system", -      content: systemMsgContent, -    }); -    return messages; -  }, [highlightedCode, chatMessages, includeHighlightedCode, writeToEditor]); - -  useEffect(() => { -    if ( -      chatMessages.length > 0 && -      chatMessages[chatMessages.length - 1].role === "user" && -      !isStreaming -    ) { -      dispatch(setIsStreaming(true)); -      streamToStateThunk(dispatch, async () => { -        if (chatMessages.length === 0) { -          return new Promise((resolve, _) => resolve(new Response())); -        } -        let hiddenChatMessages = await compileHiddenChatMessages(); -        let augmentedMessages = [ -          ...chatMessages.slice(0, -1), -          ...hiddenChatMessages, -          chatMessages[chatMessages.length - 1], -        ]; -        console.log(augmentedMessages); -        // The autogenerated client can't handle streams, so have to go raw -        return fetch(`${baseUrl}/chat/complete`, { -          method: "POST", -          headers: { -            "Content-Type": "application/json", -          }, -          body: JSON.stringify({ -            messages: augmentedMessages, -          }), -        }); -      }); -    } -  }, [chatMessages, dispatch, isStreaming, highlightedCode]); - -  const chatMessagesDiv = useRef<HTMLDivElement>(null); -  useEffect(() => { -    // Scroll to bottom -    let interval = setInterval(() => { -      if (chatMessagesDiv.current && !waitingForResponse) { -        chatMessagesDiv.current.scrollTop += Math.max( -          4, -          0.05 * chatMessagesDiv.current.scrollHeight - -            chatMessagesDiv.current.clientHeight - -            chatMessagesDiv.current.scrollTop -        ); -        if ( -          chatMessagesDiv.current.scrollTop >= -          chatMessagesDiv.current.scrollHeight - -            chatMessagesDiv.current.clientHeight -        ) { -          clearInterval(interval); -        } -      } -    }, 10); -  }, [chatMessages, chatMessagesDiv, waitingForResponse]); - -  return ( -    <ChatContainer> -      <div className="mx-5 overflow-y-scroll" ref={chatMessagesDiv}> -        <h1>Chat</h1> -        <hr></hr> -        <div> -          {chatMessages.length > 0 ? ( -            chatMessages.map((message, idx) => { -              return <MessageDiv key={idx} {...message}></MessageDiv>; -            }) -          ) : ( -            <p className="text-gray-400 m-auto text-center"> -              You can ask questions about your codebase or ask for code written -              directly in the editor. -            </p> -          )} -          {waitingForResponse && <Loader></Loader>} -        </div> -      </div> - -      <BottomDiv> -        <div className="h-12 bg-secondary-"> -          <div className="flex items-center p-2"> -            {/* <p className="mr-auto text-xs"> -              Highlighted code is automatically included in your chat message. -            </p> */} -            <BottomButton -              className="ml-auto" -              active={writeToEditor} -              onClick={() => { -                setWriteToEditor(!writeToEditor); -              }} -            > -              {writeToEditor ? "Writing to editor" : "Write to editor"} -            </BottomButton> - -            <BottomButton -              active={includeHighlightedCode} -              onClick={() => { -                setIncludeHighlightedCode(!includeHighlightedCode); -              }} -            > -              {includeHighlightedCode -                ? "Including highlighted code" -                : "Automatically finding relevant code"} -            </BottomButton> -          </div> -        </div> -        <TextEntryBar -          type="text" -          placeholder="Enter your message here" -          onKeyDown={(e) => { -            if (e.key === "Enter" && e.currentTarget.value !== "") { -              console.log("Sending message", e.currentTarget.value); -              dispatch( -                addMessage({ content: e.currentTarget.value, role: "user" }) -              ); -              (e.target as any).value = ""; -              setWaitingForResponse(true); -            } -          }} -        ></TextEntryBar> -      </BottomDiv> -    </ChatContainer> -  ); -} - -export default ChatTab; diff --git a/extension/react-app/src/tabs/main.tsx b/extension/react-app/src/tabs/main.tsx deleted file mode 100644 index a8b3300d..00000000 --- a/extension/react-app/src/tabs/main.tsx +++ /dev/null @@ -1,189 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { H3, TextArea, Button, Pre, Loader } from "../components"; -import styled from "styled-components"; -import { postVscMessage, withProgress } from "../vscode"; -import { useDebugContextValue } from "../redux/hooks"; -import CodeMultiselect from "../components/CodeMultiselect"; -import { useSelector } from "react-redux"; -import { selectDebugContext } from "../redux/selectors/debugContextSelectors"; -import { useDispatch } from "react-redux"; -import { updateValue } from "../redux/slices/debugContexSlice"; -import { setWorkspacePath } from "../redux/slices/configSlice"; -import { SerializedDebugContext } from "../../../src/client"; -import { useEditCache } from "../util/editCache"; -import { useApi } from "../util/api"; - -const ButtonDiv = styled.div` -  display: flex; -  justify-content: space-between; -  align-items: center; -  gap: 4px; -  margin: 4px; -  flex-wrap: wrap; - -  & button { -    flex-grow: 1; -  } -`; - -function MainTab(props: any) { -  const dispatch = useDispatch(); - -  const [suggestion, setSuggestion] = useState(""); -  const [traceback, setTraceback] = useDebugContextValue("traceback", ""); -  const [selectedRanges, setSelectedRanges] = useDebugContextValue( -    "rangesInFiles", -    [] -  ); - -  const editCache = useEditCache(); -  const { debugApi } = useApi(); - -  const [responseLoading, setResponseLoading] = useState(false); - -  let debugContext = useSelector(selectDebugContext); - -  useEffect(() => { -    editCache.preloadEdit(debugContext); -  }, [debugContext]); - -  function postVscMessageWithDebugContext( -    type: string, -    overrideDebugContext: SerializedDebugContext | null = null -  ) { -    postVscMessage(type, { -      debugContext: overrideDebugContext || debugContext, -    }); -  } - -  function launchFindSuspiciousCode(newTraceback: string) { -    // setTraceback's effects don't occur immediately, so we have to add it to the debug context manually -    let updatedDebugContext = { -      ...debugContext, -      traceback: newTraceback, -    }; -    postVscMessageWithDebugContext("findSuspiciousCode", updatedDebugContext); -    postVscMessageWithDebugContext("preloadEdit", updatedDebugContext); -  } - -  useEffect(() => { -    const eventListener = (event: any) => { -      switch (event.data.type) { -        case "suggestFix": -        case "explainCode": -        case "listTenThings": -          setSuggestion(event.data.value); -          setResponseLoading(false); -          break; -        case "traceback": -          setTraceback(event.data.value); -          launchFindSuspiciousCode(event.data.value); -          break; -        case "workspacePath": -          dispatch(setWorkspacePath(event.data.value)); -          break; -      } -    }; -    window.addEventListener("message", eventListener); - -    return () => window.removeEventListener("message", eventListener); -  }, [debugContext, selectedRanges]); - -  return ( -    <div className="mx-5"> -      <h1>Debug Panel</h1> - -      <H3>Code Sections</H3> -      <CodeMultiselect></CodeMultiselect> - -      <H3>Bug Description</H3> -      <TextArea -        id="bugDescription" -        name="bugDescription" -        className="bugDescription" -        rows={4} -        cols={50} -        placeholder="Describe your bug..." -      ></TextArea> - -      <H3>Stack Trace</H3> -      <TextArea -        id="traceback" -        className="traceback" -        name="traceback" -        rows={4} -        cols={50} -        placeholder="Paste stack trace here" -        onChange={(e) => { -          setTraceback(e.target.value); -          dispatch(updateValue({ key: "traceback", value: e.target.value })); -          // postVscMessageWithDebugContext("findSuspiciousCode"); -        }} -        onPaste={(e) => { -          let pasted = e.clipboardData.getData("text"); -          console.log("PASTED", pasted); -          setTraceback(pasted); -          launchFindSuspiciousCode(pasted); -        }} -        value={traceback} -      ></TextArea> - -      <select -        hidden -        id="relevantVars" -        className="relevantVars" -        name="relevantVars" -      ></select> - -      <ButtonDiv> -        <Button -          onClick={() => { -            postVscMessageWithDebugContext("explainCode"); -            setResponseLoading(true); -          }} -        > -          Explain Code -        </Button> -        <Button -          onClick={() => { -            postVscMessageWithDebugContext("suggestFix"); -            setResponseLoading(true); -          }} -        > -          Generate Ideas -        </Button> -        <Button -          disabled={selectedRanges.length === 0} -          onClick={async () => { -            withProgress("Generating Fix", async () => { -              let edits = await editCache.getEdit(debugContext); -              postVscMessage("makeEdit", { edits }); -            }); -          }} -        > -          Suggest Fix -        </Button> -        <Button -          disabled={selectedRanges.length === 0} -          onClick={() => { -            postVscMessageWithDebugContext("generateUnitTest"); -          }} -        > -          Create Test -        </Button> -      </ButtonDiv> -      <Loader hidden={!responseLoading}></Loader> - -      <Pre -        className="fixSuggestion" -        hidden={!(typeof suggestion === "string" && suggestion.length > 0)} -      > -        {suggestion} -      </Pre> - -      <br></br> -    </div> -  ); -} - -export default MainTab; diff --git a/extension/react-app/src/tabs/welcome.tsx b/extension/react-app/src/tabs/welcome.tsx deleted file mode 100644 index c29d260a..00000000 --- a/extension/react-app/src/tabs/welcome.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; - -function WelcomeTab() { -  return ( -    <div className="mx-5"> -      <h1>Welcome to Continue</h1> - -      <p> -        Learn more in the{" "} -        <a href="https://www.notion.so/continue-dev/Continue-User-Guide-1c6ad99887d0474d9e42206f6c98efa4"> -          Continue User Guide -        </a>{" "} -      </p> -      <p>Send Nate or Ty your feedback:</p> -      <p>1. What excites you about Continue?</p> -      <p>2. What did you struggle with when using Continue?</p> -      <p>3. How do you wish Continue worked?</p> -    </div> -  ); -} - -export default WelcomeTab; | 
