From f09150617ed2454f3074bcf93f53aae5ae637d40 Mon Sep 17 00:00:00 2001 From: Nate Sesti <33237525+sestinj@users.noreply.github.com> Date: Mon, 9 Oct 2023 18:37:27 -0700 Subject: Preview (#541) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Strong typing (#533) * refactor: :recycle: get rid of continuedev.src.continuedev structure * refactor: :recycle: switching back to server folder * feat: :sparkles: make config.py imports shorter * feat: :bookmark: publish as pre-release vscode extension * refactor: :recycle: refactor and add more completion params to ui * build: :building_construction: download from preview S3 * fix: :bug: fix paths * fix: :green_heart: package:pre-release * ci: :green_heart: more time for tests * fix: :green_heart: fix build scripts * fix: :bug: fix import in run.py * fix: :bookmark: update version to try again * ci: 💚 Update package.json version [skip ci] * refactor: :fire: don't check for old extensions version * fix: :bug: small bug fixes * fix: :bug: fix config.py import paths * ci: 💚 Update package.json version [skip ci] * ci: :green_heart: platform-specific builds test #1 * feat: :green_heart: ship with binary * fix: :green_heart: fix copy statement to include.exe for windows * fix: :green_heart: cd extension before packaging * chore: :loud_sound: count tokens generated * fix: :green_heart: remove npm_config_arch * fix: :green_heart: publish as pre-release! * chore: :bookmark: update version * perf: :green_heart: hardcode distro paths * fix: :bug: fix yaml syntax error * chore: :bookmark: update version * fix: :green_heart: update permissions and version * feat: :bug: kill old server if needed * feat: :lipstick: update marketplace icon for pre-release * ci: 💚 Update package.json version [skip ci] * feat: :sparkles: auto-reload for config.py * feat: :wrench: update default config.py imports * feat: :sparkles: codelens in config.py * feat: :sparkles: select model param count from UI * ci: 💚 Update package.json version [skip ci] * feat: :sparkles: more model options, ollama error handling * perf: :zap: don't show server loading immediately * fix: :bug: fixing small UI details * ci: 💚 Update package.json version [skip ci] * feat: :rocket: headers param on LLM class * fix: :bug: fix headers for openai.;y * feat: :sparkles: highlight code on cmd+shift+L * ci: 💚 Update package.json version [skip ci] * feat: :lipstick: sticky top bar in gui.tsx * fix: :loud_sound: websocket logging and horizontal scrollbar * ci: 💚 Update package.json version [skip ci] * feat: :sparkles: allow AzureOpenAI Service through GGML * ci: 💚 Update package.json version [skip ci] * fix: :bug: fix automigration * ci: 💚 Update package.json version [skip ci] * ci: :green_heart: upload binaries in ci, download apple silicon * chore: :fire: remove notes * fix: :green_heart: use curl to download binary * fix: :green_heart: set permissions on apple silicon binary * fix: :green_heart: testing * fix: :green_heart: cleanup file * fix: :green_heart: fix preview.yaml * fix: :green_heart: only upload once per binary * fix: :green_heart: install rosetta * ci: :green_heart: download binary after tests * ci: 💚 Update package.json version [skip ci] * ci: :green_heart: prepare ci for merge to main --------- Co-authored-by: GitHub Action --- extension/package-lock.json | 4 +- extension/package.json | 5 +- extension/react-app/package-lock.json | 1 + extension/react-app/package.json | 1 + extension/react-app/public/logos/mistral.png | Bin 0 -> 5020 bytes extension/react-app/public/logos/wizardlm.png | Bin 0 -> 494793 bytes extension/react-app/src/components/ComboBox.tsx | 31 +- .../src/components/ErrorStepContainer.tsx | 2 +- extension/react-app/src/components/Layout.tsx | 29 +- extension/react-app/src/components/ModelCard.tsx | 178 +++++--- .../react-app/src/components/ModelSettings.tsx | 6 +- extension/react-app/src/components/Suggestions.tsx | 17 +- .../components/dialogs/AddContextGroupDialog.tsx | 4 +- .../react-app/src/components/dialogs/FTCDialog.tsx | 5 +- extension/react-app/src/components/index.ts | 13 +- extension/react-app/src/pages/gui.tsx | 10 +- extension/react-app/src/pages/history.tsx | 6 +- extension/react-app/src/pages/modelconfig.tsx | 63 ++- extension/react-app/src/pages/models.tsx | 3 - extension/react-app/src/pages/settings.tsx | 11 +- extension/react-app/src/util/modelData.ts | 451 ++++++++++++++++----- extension/schema/ContinueConfig.d.ts | 5 + extension/schema/LLM.d.ts | 5 + extension/schema/Models.d.ts | 5 + extension/scripts/package.js | 9 +- extension/src/activation/activate.ts | 62 +-- extension/src/activation/environmentSetup.ts | 218 ++++++---- extension/src/commands.ts | 15 + extension/src/continueIdeClient.ts | 26 -- extension/src/lang-server/codeLens.ts | 62 +++ extension/src/test-suite/environmentSetup.test.ts | 4 +- extension/src/util/messenger.ts | 9 + 32 files changed, 899 insertions(+), 361 deletions(-) create mode 100644 extension/react-app/public/logos/mistral.png create mode 100644 extension/react-app/public/logos/wizardlm.png (limited to 'extension') diff --git a/extension/package-lock.json b/extension/package-lock.json index 9d9b3e19..31de1c7a 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.412", + "version": "0.1.14", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.412", + "version": "0.1.14", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 0e25fcca..6b7bee81 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1,7 +1,7 @@ { "name": "continue", "icon": "media/icon.png", - "version": "0.0.412", + "version": "0.1.14", "repository": { "type": "git", "url": "https://github.com/continuedev/continue" @@ -213,7 +213,8 @@ "build-test": "tsc && node esbuild.test.mjs", "test": "npm run build-test && node ./out/test-runner/runTestOnVSCodeHost.js", "prepackage": "node scripts/prepackage.js", - "package": "node scripts/package.js" + "package": "node scripts/package.js", + "package:pre-release": "node scripts/package.js --pre-release" }, "devDependencies": { "@nestjs/common": "^8.4.7", diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json index fb68081c..a52396ef 100644 --- a/extension/react-app/package-lock.json +++ b/extension/react-app/package-lock.json @@ -11,6 +11,7 @@ "@types/vscode-webview": "^1.57.1", "@uiw/react-markdown-preview": "^4.1.13", "downshift": "^7.6.0", + "lodash": "^4.17.21", "meilisearch": "^0.33.0", "posthog-js": "^1.58.0", "prismjs": "^1.29.0", diff --git a/extension/react-app/package.json b/extension/react-app/package.json index b9f70645..be23b34b 100644 --- a/extension/react-app/package.json +++ b/extension/react-app/package.json @@ -12,6 +12,7 @@ "@types/vscode-webview": "^1.57.1", "@uiw/react-markdown-preview": "^4.1.13", "downshift": "^7.6.0", + "lodash": "^4.17.21", "meilisearch": "^0.33.0", "posthog-js": "^1.58.0", "prismjs": "^1.29.0", diff --git a/extension/react-app/public/logos/mistral.png b/extension/react-app/public/logos/mistral.png new file mode 100644 index 00000000..0f535f84 Binary files /dev/null and b/extension/react-app/public/logos/mistral.png differ diff --git a/extension/react-app/public/logos/wizardlm.png b/extension/react-app/public/logos/wizardlm.png new file mode 100644 index 00000000..a420cf03 Binary files /dev/null and b/extension/react-app/public/logos/wizardlm.png differ diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index c08c05de..1d0ca1a5 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -285,15 +285,13 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { useEffect(() => { if (!inputRef.current) return; - if (inputRef.current.scrollHeight > inputRef.current.clientHeight) { - inputRef.current.style.height = "auto"; - inputRef.current.style.height = - Math.min(inputRef.current.scrollHeight, 300) + "px"; - } + inputRef.current.style.height = "auto"; + inputRef.current.style.height = + Math.min(inputRef.current.scrollHeight, 300) + "px"; }, [ inputRef.current?.scrollHeight, inputRef.current?.clientHeight, - props.value, + inputRef.current?.value, ]); // Whether the current input follows an '@' and should be treated as context query @@ -344,7 +342,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { useEffect(() => { if (!nestedContextProvider) { - dispatch(setTakenActionTrue(null)); setItems( contextProviders?.map((provider) => ({ name: provider.display_title, @@ -437,7 +434,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { setNestedContextProvider(undefined); // Handle slash commands - dispatch(setTakenActionTrue(null)); setItems( availableSlashCommands?.filter((slashCommand) => { const sc = slashCommand.name.toLowerCase(); @@ -445,6 +441,10 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { return sc.startsWith(iv) && sc !== iv; }) || [] ); + + if (inputValue.startsWith("/") || inputValue.startsWith("@")) { + dispatch(setTakenActionTrue(null)); + } }, [ availableSlashCommands, @@ -756,6 +756,8 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { props.index ); inputRef.current?.focus(); + setPreviewingContextItem(undefined); + setFocusedContextItem(undefined); }} onKeyDown={(e: any) => { if (e.key === "Backspace") { @@ -880,6 +882,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { paddingLeft: "12px", cursor: "default", paddingTop: getFontSize(), + width: "fit-content", }} > {props.active ? "Using" : "Used"} {selectedContextItems.length}{" "} @@ -937,17 +940,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { {...getInputProps({ onCompositionStart: () => setIsComposing(true), onCompositionEnd: () => setIsComposing(false), - onChange: (e) => { - const target = e.target as HTMLTextAreaElement; - // Update the height of the textarea to match the content, up to a max of 200px. - target.style.height = "auto"; - target.style.height = `${Math.min( - target.scrollHeight, - 300 - ).toString()}px`; - - // setShowContextDropdown(target.value.endsWith("@")); - }, + onChange: (e) => {}, onFocus: (e) => { setInputFocused(true); dispatch(setBottomMessage(undefined)); diff --git a/extension/react-app/src/components/ErrorStepContainer.tsx b/extension/react-app/src/components/ErrorStepContainer.tsx index 666780c5..07c0a046 100644 --- a/extension/react-app/src/components/ErrorStepContainer.tsx +++ b/extension/react-app/src/components/ErrorStepContainer.tsx @@ -42,7 +42,7 @@ function ErrorStepContainer(props: ErrorStepContainerProps) {
-
+        
           {props.historyNode.observation?.error as string}
         
diff --git a/extension/react-app/src/components/Layout.tsx b/extension/react-app/src/components/Layout.tsx index a54c0ed4..db31c8db 100644 --- a/extension/react-app/src/components/Layout.tsx +++ b/extension/react-app/src/components/Layout.tsx @@ -30,6 +30,20 @@ const LayoutTopDiv = styled.div` border-radius: ${defaultBorderRadius}; scrollbar-base-color: transparent; scrollbar-width: thin; + + & * { + ::-webkit-scrollbar { + width: 4px; + } + + ::-webkit-scrollbar:horizontal { + height: 4px; + } + + ::-webkit-scrollbar-thumb { + border-radius: 2px; + } + } `; const BottomMessageDiv = styled.div<{ displayOnBottom: boolean }>` @@ -47,7 +61,6 @@ const BottomMessageDiv = styled.div<{ displayOnBottom: boolean }>` z-index: 100; box-shadow: 0px 0px 2px 0px ${vscForeground}; max-height: 35vh; - overflow: scroll; `; const Footer = styled.footer` @@ -131,6 +144,20 @@ const Layout = () => { }; }, [client, timeline]); + useEffect(() => { + const handler = (event: any) => { + if (event.data.type === "addModel") { + navigate("/models"); + } else if (event.data.type === "openSettings") { + navigate("/settings"); + } + }; + window.addEventListener("message", handler); + return () => { + window.removeEventListener("message", handler); + }; + }, []); + return (
` +const Div = styled.div<{ color: string; disabled: boolean; hovered: boolean }>` border: 1px solid ${lightGray}; border-radius: ${defaultBorderRadius}; - padding: 4px 8px; position: relative; width: 100%; transition: all 0.5s; @@ -20,13 +20,45 @@ const Div = styled.div<{ color: string; disabled: boolean }>` ? ` opacity: 0.5; ` - : ` - &:hover { + : props.hovered + ? ` border: 1px solid ${props.color}; background-color: ${props.color}22; + cursor: pointer;` + : ""} +`; + +const DimensionsDiv = styled.div` + display: flex; + justify-content: flex-end; + margin-left: auto; + padding: 4px; + /* width: fit-content; */ + + border-top: 1px solid ${lightGray}; +`; + +const DimensionOptionDiv = styled.div<{ selected: boolean }>` + display: flex; + flex-direction: column; + align-items: center; + margin-right: 8px; + background-color: ${lightGray}; + padding: 4px; + border-radius: ${defaultBorderRadius}; + outline: 0.5px solid ${lightGray}; + + ${(props) => + props.selected && + ` + background-color: ${buttonColor}; + color: white; + `} + + &:hover { cursor: pointer; + outline: 1px solid ${buttonColor}; } - `} `; interface ModelCardProps { @@ -35,8 +67,12 @@ interface ModelCardProps { tags?: string[]; refUrl?: string; icon?: string; - onClick: (e: React.MouseEvent) => void; + onClick: ( + e: React.MouseEvent, + dimensionChoices?: string[] + ) => void; disabled?: boolean; + dimensions?: PackageDimension[]; } function ModelCard(props: ModelCardProps) { @@ -44,53 +80,103 @@ function ModelCard(props: ModelCardProps) { (state: RootStore) => state.config.vscMediaUrl ); + const [dimensionChoices, setDimensionChoices] = useState( + props.dimensions?.map((d) => Object.keys(d.options)[0]) || [] + ); + + const [hovered, setHovered] = useState(false); + return (
props.onClick(e)} + hovered={hovered} > -
- {vscMediaUrl && props.icon && ( - - )} -

{props.title}

-
- {props.tags?.map((tag) => { - return ( - setHovered(true)} + onMouseLeave={() => setHovered(false)} + className="px-2 py-1" + onClick={ + props.disabled + ? undefined + : (e) => { + if ((e.target as any).closest("a")) { + return; + } + props.onClick(e, dimensionChoices); + } + } + > +
+ {vscMediaUrl && props.icon && ( + + )} +

{props.title}

+
+ {props.tags?.map((tag) => { + return ( + + {tag} + + ); + })} +

{props.description}

+ + {props.refUrl && ( + - {tag} -
- ); - })} -

{props.description}

+ + + +
+ )} +
- {props.refUrl && ( - - - - - + {props.dimensions?.length && ( + + {props.dimensions?.map((dimension, i) => { + return ( +
+ +

{dimension.name}

+ {Object.keys(dimension.options).map((key) => { + return ( + { + e.stopPropagation(); + const newChoices = [...dimensionChoices]; + newChoices[i] = key; + setDimensionChoices(newChoices); + }} + selected={dimensionChoices[i] === key} + > + {key} + + ); + })} +
+ ); + })} +
)}
); diff --git a/extension/react-app/src/components/ModelSettings.tsx b/extension/react-app/src/components/ModelSettings.tsx index 4b9d5e64..3f9414b1 100644 --- a/extension/react-app/src/components/ModelSettings.tsx +++ b/extension/react-app/src/components/ModelSettings.tsx @@ -3,7 +3,7 @@ import { LLM } from "../../../schema/LLM"; import { Label, Select, - TextInput, + Input, defaultBorderRadius, lightGray, vscForeground, @@ -58,7 +58,7 @@ function ModelSettings(props: { llm: any | undefined; role: string }) { {typeof modelOptions.api_key !== undefined && ( <> - - ` border-radius: ${defaultBorderRadius}; @@ -159,6 +160,7 @@ const TutorialDiv = styled.div` `; function SuggestionsArea(props: { onClick: (textInput: string) => void }) { + const posthog = usePostHog(); const [stage, setStage] = useState( parseInt(localStorage.getItem("stage") || "0") ); @@ -207,8 +209,18 @@ function SuggestionsArea(props: { onClick: (textInput: string) => void }) { className="absolute right-1 top-1 cursor-pointer" text="Close Tutorial" onClick={() => { - console.log("HIDE"); setHide(true); + const tutorialClosedCount = parseInt( + localStorage.getItem("tutorialClosedCount") || "0" + ); + localStorage.setItem( + "tutorialClosedCount", + (tutorialClosedCount + 1).toString() + ); + posthog?.capture("tutorial_closed", { + stage, + tutorialClosedCount, + }); }} > @@ -219,8 +231,9 @@ function SuggestionsArea(props: { onClick: (textInput: string) => void }) { disabled={!codeIsHighlighted} {...suggestion} onClick={() => { - if (stage > 0 && !codeIsHighlighted) return; + if (!codeIsHighlighted) return; props.onClick(suggestion.textInput); + posthog?.capture("tutorial_stage_complete", { stage }); setStage(stage + 1); localStorage.setItem("stage", (stage + 1).toString()); setHide(true); diff --git a/extension/react-app/src/components/dialogs/AddContextGroupDialog.tsx b/extension/react-app/src/components/dialogs/AddContextGroupDialog.tsx index 9cd0a95e..a6cf151c 100644 --- a/extension/react-app/src/components/dialogs/AddContextGroupDialog.tsx +++ b/extension/react-app/src/components/dialogs/AddContextGroupDialog.tsx @@ -1,5 +1,5 @@ import { useContext } from "react"; -import { Button, TextInput } from ".."; +import { Button, Input } from ".."; import { GUIClientContext } from "../../App"; import { useDispatch } from "react-redux"; import { @@ -27,7 +27,7 @@ function AddContextGroupDialog({ return (
- { diff --git a/extension/react-app/src/components/dialogs/FTCDialog.tsx b/extension/react-app/src/components/dialogs/FTCDialog.tsx index 3ea753bc..5fa2d4e6 100644 --- a/extension/react-app/src/components/dialogs/FTCDialog.tsx +++ b/extension/react-app/src/components/dialogs/FTCDialog.tsx @@ -1,6 +1,6 @@ import React, { useContext } from "react"; import styled from "styled-components"; -import { Button, TextInput } from ".."; +import { Button, Input } from ".."; import { useNavigate } from "react-router-dom"; import { GUIClientContext } from "../../App"; import { useDispatch } from "react-redux"; @@ -37,7 +37,7 @@ function FTCDialog() { OpenAIFreeTrial object.

-