Skip to content

Commit f97e639

Browse files
Patrick-Erichsensestinj
authored andcommitted
chore: onboarding metrics (#1626)
* fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs
1 parent b8bdcbd commit f97e639

12 files changed

+277
-37
lines changed

.vscode/tasks.json

+1-3
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
// To bundle the code the same way we do for publishing
1313
"vscode-extension:esbuild",
1414
// Start the React app that is used in the extension
15-
"gui:dev",
16-
// Start the docs site, without opening the browser
17-
"docs:start"
15+
"gui:dev"
1816
],
1917
"group": {
2018
"kind": "build",

gui/src/components/Layout.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
} from ".";
1616
import { IdeMessengerContext } from "../context/IdeMessenger";
1717
import { useWebviewListener } from "../hooks/useWebviewListener";
18+
import { shouldBeginOnboarding } from "../pages/onboarding/utils";
1819
import { defaultModelSelector } from "../redux/selectors/modelSelectors";
1920
import {
2021
setBottomMessage,
@@ -212,9 +213,8 @@ const Layout = () => {
212213
);
213214

214215
useEffect(() => {
215-
const onboardingComplete = getLocalStorage("onboardingComplete");
216216
if (
217-
!onboardingComplete &&
217+
shouldBeginOnboarding() &&
218218
(location.pathname === "/" || location.pathname === "/index.html")
219219
) {
220220
navigate("/onboarding");

gui/src/components/PosthogPageView.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@ import { useSearchParams, useLocation } from "react-router-dom";
88
*/
99
export default function PostHogPageView() {
1010
const { pathname } = useLocation();
11-
const searchParams = useSearchParams();
11+
const [searchParams] = useSearchParams();
1212
const posthog = usePostHog();
1313

1414
// Track pageviews
1515
useEffect(() => {
1616
if (pathname && posthog) {
1717
let url = window.origin + pathname;
18+
1819
if (searchParams.toString()) {
1920
url = url + `?${searchParams.toString()}`;
2021
}
22+
2123
posthog.capture("$pageview", {
2224
$current_url: url,
2325
});

gui/src/components/dialogs/KeyboardShortcuts.tsx

+13-14
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
lightGray,
77
vscForeground,
88
} from "..";
9-
import { getPlatform } from "../../util";
9+
import { getPlatform, isJetBrains } from "../../util";
1010

1111
const GridDiv = styled.div`
1212
display: grid;
@@ -209,19 +209,18 @@ function KeyboardShortcutsDialog() {
209209
<div className="p-2">
210210
<h3 className="my-3 mx-auto text-center">Keyboard Shortcuts</h3>
211211
<GridDiv>
212-
{(localStorage.getItem("ide") === "jetbrains"
213-
? jetbrainsShortcuts
214-
: vscodeShortcuts
215-
).map((shortcut, i) => {
216-
return (
217-
<KeyboardShortcut
218-
key={i}
219-
mac={shortcut.mac}
220-
windows={shortcut.windows}
221-
description={shortcut.description}
222-
/>
223-
);
224-
})}
212+
{(isJetBrains() ? jetbrainsShortcuts : vscodeShortcuts).map(
213+
(shortcut, i) => {
214+
return (
215+
<KeyboardShortcut
216+
key={i}
217+
mac={shortcut.mac}
218+
windows={shortcut.windows}
219+
description={shortcut.description}
220+
/>
221+
);
222+
},
223+
)}
225224
</GridDiv>
226225
</div>
227226
);

gui/src/components/modelSelection/quickSetup/GitHubSignInButton.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ function GitHubSignInButton(props: GitHubSignInButtonProps) {
3131
xmlns="http://www.w3.org/2000/svg"
3232
>
3333
<path
34-
fill-rule="evenodd"
35-
clip-rule="evenodd"
34+
fillRule="evenodd"
35+
clipRule="evenodd"
3636
d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"
3737
fill={vscForeground}
3838
/>
@@ -73,8 +73,8 @@ function GitHubSignInButton(props: GitHubSignInButtonProps) {
7373
>
7474
<svg viewBox="0 0 98 96" height={24} xmlns="http://www.w3.org/2000/svg">
7575
<path
76-
fill-rule="evenodd"
77-
clip-rule="evenodd"
76+
fillRule="evenodd"
77+
clipRule="evenodd"
7878
d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"
7979
fill={vscForeground}
8080
/>

gui/src/pages/onboarding/ApiKeysOnboarding.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@ import QuickModelSetup from "../../components/modelSelection/quickSetup/QuickMod
66
import { getLocalStorage } from "../../util/localStorage";
77
import Toggle from "../../components/modelSelection/Toggle";
88
import DefaultModelConfigForm from "./DefaultModelConfigForm";
9+
import { useOnboarding } from "./utils";
910

1011
function ApiKeysOnboarding() {
1112
const ideMessenger = useContext(IdeMessengerContext);
1213
const navigate = useNavigate();
1314

14-
// Controls the toggle between default and custom model setup
1515
const [isBestToggle, setIsBestToggle] = useState(true);
1616

17+
const { completeOnboarding } = useOnboarding();
18+
1719
return (
1820
<div className="p-8 overflow-y-scroll">
1921
<div>
@@ -50,7 +52,7 @@ function ApiKeysOnboarding() {
5052
ideMessenger.post("showTutorial", undefined);
5153

5254
if (getLocalStorage("signedInToGh")) {
53-
navigate("/");
55+
completeOnboarding();
5456
} else {
5557
navigate("/apiKeyAutocompleteOnboarding");
5658
}

gui/src/pages/onboarding/DefaultModelConfigForm.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { useContext, useState } from "react";
22
import { useDispatch } from "react-redux";
3-
import { useNavigate } from "react-router-dom";
43
import styled from "styled-components";
54
import { Input, lightGray } from "../../components";
65
import { IdeMessengerContext } from "../../context/IdeMessenger";
76
import { setDefaultModel } from "../../redux/slices/stateSlice";
87
import { models } from "../AddNewModel/configs/models";
98
import { providers } from "../AddNewModel/configs/providers";
109
import { StyledButton } from "./components";
10+
import { useOnboarding } from "./utils";
1111

1212
const HelperText = styled.p`
1313
font-size: 0.8rem;
@@ -16,14 +16,15 @@ const HelperText = styled.p`
1616
`;
1717

1818
function DefaultModelConfigForm() {
19-
const navigate = useNavigate();
2019
const dispatch = useDispatch();
2120

2221
const ideMessenger = useContext(IdeMessengerContext);
2322

2423
const [mistralApiKey, setMistralApiKey] = useState("");
2524
const [anthropicApiKey, setAnthropicApiKey] = useState("");
2625

26+
const { completeOnboarding } = useOnboarding();
27+
2728
const isFormComplete = !!mistralApiKey && !!anthropicApiKey;
2829

2930
const { anthropic, mistral } = providers;
@@ -56,7 +57,7 @@ function DefaultModelConfigForm() {
5657

5758
ideMessenger.post("showTutorial", undefined);
5859

59-
navigate("/");
60+
completeOnboarding();
6061
}
6162

6263
return (

gui/src/pages/onboarding/LocalOnboarding.tsx

+4-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { CopyToTerminalButton } from "./CopyToTerminalButton";
66
import { CheckMarkHeader } from "./CheckMarkHeader";
77
import { ONBOARDING_LOCAL_MODEL_TITLE } from "core/config/onboarding";
88
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
9+
import { useOnboarding } from "./utils";
910

1011
type OllamaConnectionStatuses =
1112
| "waiting_to_download"
@@ -34,11 +35,9 @@ function LocalOnboarding() {
3435

3536
const [hasLoadedChatModel, setHasLoadedChatModel] = useState(false);
3637

37-
const isOllamaConnected = ollamaConnectionStatus === "verified";
38+
const { completeOnboarding } = useOnboarding();
3839

39-
function handleCompleteClick() {
40-
navigate("/");
41-
}
40+
const isOllamaConnected = ollamaConnectionStatus === "verified";
4241

4342
function isModelDownloaded(model: string) {
4443
if (!downloadedOllamaModels) {
@@ -219,7 +218,7 @@ function LocalOnboarding() {
219218
</div>
220219

221220
<div className="flex flex-col justify-end mt-4">
222-
<StyledButton onClick={handleCompleteClick}>
221+
<StyledButton onClick={completeOnboarding}>
223222
Complete onboarding
224223
</StyledButton>
225224
</div>
+184
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import {
2+
CheckBadgeIcon,
3+
GiftIcon,
4+
Cog6ToothIcon,
5+
ComputerDesktopIcon,
6+
} from "@heroicons/react/24/outline";
7+
import { ToCoreFromIdeOrWebviewProtocol } from "core/protocol/core";
8+
import { useContext, useState } from "react";
9+
import { useNavigate } from "react-router-dom";
10+
import GitHubSignInButton from "../../components/modelSelection/quickSetup/GitHubSignInButton";
11+
import { IdeMessengerContext } from "../../context/IdeMessenger";
12+
import { isJetBrains } from "../../util";
13+
import { Div, StyledButton } from "./components";
14+
import { FREE_TRIAL_LIMIT_REQUESTS, hasPassedFTL } from "../../util/freeTrial";
15+
import { useOnboarding } from "./utils";
16+
17+
type OnboardingMode =
18+
ToCoreFromIdeOrWebviewProtocol["completeOnboarding"][0]["mode"];
19+
20+
function Onboarding() {
21+
const navigate = useNavigate();
22+
const ideMessenger = useContext(IdeMessengerContext);
23+
24+
const [hasSignedIntoGh, setHasSignedIntoGh] = useState(false);
25+
const [selectedOnboardingMode, setSlectedOnboardingMode] = useState<
26+
OnboardingMode | undefined
27+
>(undefined);
28+
29+
const { completeOnboarding } = useOnboarding();
30+
31+
function onSubmit() {
32+
ideMessenger.post("completeOnboarding", {
33+
mode: selectedOnboardingMode,
34+
});
35+
36+
/**
37+
* "completeOnboarding" above will update the config with our
38+
* new embeddings provider. If it's not the default local provider,
39+
* we need to re-index the codebase.
40+
*/
41+
if (selectedOnboardingMode !== "local") {
42+
ideMessenger.post("index/forceReIndex", undefined);
43+
}
44+
45+
switch (selectedOnboardingMode) {
46+
case "local":
47+
navigate("/localOnboarding");
48+
break;
49+
50+
case "apiKeys":
51+
navigate("/apiKeysOnboarding");
52+
break;
53+
54+
case "freeTrial":
55+
completeOnboarding();
56+
break;
57+
58+
default:
59+
break;
60+
}
61+
}
62+
63+
return (
64+
<div className="max-w-96 mx-auto leading-normal">
65+
<div className="leading-relaxed">
66+
<h1 className="text-center">Welcome to Continue</h1>
67+
<p className="text-center ">
68+
Let's find the setup that works best for you. You can update your
69+
configuration after onboarding by clicking the
70+
<Cog6ToothIcon className="inline-block h-5 w-5 align-middle px-1" />
71+
icon in the bottom-right corner of Continue.
72+
</p>
73+
</div>
74+
75+
<div className="flex flex-col gap-6 pb-8 pt-4">
76+
{(!hasPassedFTL() || isJetBrains()) && (
77+
<Div
78+
selected={selectedOnboardingMode === "freeTrial"}
79+
onClick={() => setSlectedOnboardingMode("freeTrial")}
80+
>
81+
<h3>
82+
<GiftIcon
83+
width="1.4em"
84+
height="1.4em"
85+
className="align-middle pr-2"
86+
/>
87+
Free trial
88+
</h3>
89+
<p>
90+
Start your free trial of {FREE_TRIAL_LIMIT_REQUESTS} requests by
91+
signing into GitHub.
92+
</p>
93+
94+
<ul className="pl-4 mb-0">
95+
<li>
96+
<b>Chat:</b> Llama 3 with Ollama, LM Studio, etc.
97+
</li>
98+
<li>
99+
<b>Embeddings:</b> Nomic Embed
100+
</li>
101+
<li>
102+
<b>Autocomplete:</b> Starcoder2 3B
103+
</li>
104+
</ul>
105+
106+
{!hasSignedIntoGh && (
107+
<div className="flex justify-center py-3">
108+
<GitHubSignInButton
109+
onComplete={() => setHasSignedIntoGh(true)}
110+
></GitHubSignInButton>
111+
</div>
112+
)}
113+
</Div>
114+
)}
115+
<Div
116+
selected={selectedOnboardingMode === "local"}
117+
onClick={() => setSlectedOnboardingMode("local")}
118+
>
119+
<h3>
120+
<ComputerDesktopIcon
121+
width="1.4em"
122+
height="1.4em"
123+
className="align-middle pr-2"
124+
/>
125+
Local models
126+
</h3>
127+
<p>
128+
No code will leave your computer, but less powerful models are used.
129+
</p>
130+
131+
<ul className="pl-4 ">
132+
<li>
133+
<b>Chat:</b> Llama 3 with Ollama, LM Studio, etc.
134+
</li>
135+
<li>
136+
<b>Embeddings:</b> Nomic Embed
137+
</li>
138+
<li>
139+
<b>Autocomplete:</b> Starcoder2 3B
140+
</li>
141+
</ul>
142+
</Div>
143+
144+
<Div
145+
selected={selectedOnboardingMode === "apiKeys"}
146+
onClick={() => setSlectedOnboardingMode("apiKeys")}
147+
>
148+
<h3>
149+
<CheckBadgeIcon
150+
width="1.4em"
151+
height="1.4em"
152+
className="align-middle pr-2"
153+
/>
154+
Best experience
155+
</h3>
156+
<p>
157+
Start with the most powerful models available, or customize your own
158+
configuration.
159+
</p>
160+
161+
<ul className="pl-4 ">
162+
<li>
163+
<b>Chat:</b> Claude 3.5 Sonnet
164+
</li>
165+
<li>
166+
<b>Embeddings:</b> Voyage Code 2
167+
</li>
168+
<li>
169+
<b>Autocomplete:</b> Codestral
170+
</li>
171+
</ul>
172+
</Div>
173+
</div>
174+
175+
<div className="flex justify-end">
176+
<StyledButton disabled={!selectedOnboardingMode} onClick={onSubmit}>
177+
Continue
178+
</StyledButton>
179+
</div>
180+
</div>
181+
);
182+
}
183+
184+
export default Onboarding;

0 commit comments

Comments
 (0)