From 62111bd112b382988a61221f993c0781f862a105 Mon Sep 17 00:00:00 2001 From: Shohan Dutta Roy Date: Sun, 9 Jun 2024 17:41:05 +0530 Subject: [PATCH 1/6] feat: Add onboarding for new users --- openadapt/app/dashboard/api/settings.py | 4 +- openadapt/app/dashboard/app/layout.tsx | 6 +- .../dashboard/components/Onboarding/index.tsx | 72 +++++++++++++++++++ openadapt/app/tray.py | 7 +- openadapt/config.defaults.json | 3 +- openadapt/config.py | 2 + 6 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 openadapt/app/dashboard/components/Onboarding/index.tsx diff --git a/openadapt/app/dashboard/api/settings.py b/openadapt/app/dashboard/api/settings.py index c791dbe70..716203102 100644 --- a/openadapt/app/dashboard/api/settings.py +++ b/openadapt/app/dashboard/api/settings.py @@ -20,7 +20,9 @@ def attach_routes(self) -> APIRouter: self.app.add_api_route("", self.set_settings, methods=["POST"]) return self.app - Category = Literal["api_keys", "scrubbing", "record_and_replay", "general"] + Category = Literal[ + "api_keys", "scrubbing", "record_and_replay", "general", "onboarding" + ] @staticmethod def get_settings(category: Category) -> dict[str, Any]: diff --git a/openadapt/app/dashboard/app/layout.tsx b/openadapt/app/dashboard/app/layout.tsx index 52d4515c1..3dae85845 100644 --- a/openadapt/app/dashboard/app/layout.tsx +++ b/openadapt/app/dashboard/app/layout.tsx @@ -5,6 +5,7 @@ import { Notifications } from '@mantine/notifications'; import { Shell } from '@/components/Shell' import { CSPostHogProvider } from './providers'; import { ModalsProvider } from '@mantine/modals'; +import { Onboarding } from '@/components/Onboarding'; export const metadata = { title: 'OpenAdapt.AI', @@ -25,7 +26,10 @@ export default function RootLayout({ - {children} + + + {children} + diff --git a/openadapt/app/dashboard/components/Onboarding/index.tsx b/openadapt/app/dashboard/components/Onboarding/index.tsx new file mode 100644 index 000000000..917fad120 --- /dev/null +++ b/openadapt/app/dashboard/components/Onboarding/index.tsx @@ -0,0 +1,72 @@ +'use client'; + +import { get } from '@/api'; +import { Button, Checkbox, Divider, Grid, Modal, Stack, Text, TextInput } from '@mantine/core'; +import { useForm } from '@mantine/form'; +import Link from 'next/link'; +import React, { useEffect, useState } from 'react' + +export const Onboarding = () => { + const [showOnboardingModal, setShowOnboardingModal] = useState(false); + const onboardingForm = useForm({ + initialValues: { + email: '', + }, + }); + + async function fetchOnboardingStatus() { + const resp = await get<{ SHOW_ONBOARDING_MODAL: boolean }>('/api/settings?category=general', { + cache: 'no-store', + }) + return resp.SHOW_ONBOARDING_MODAL; + } + + function onClose() { + fetch('/api/settings', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ SHOW_ONBOARDING_MODAL: false }), + }).then(() => setShowOnboardingModal(false)); + } + + function onSubmit({ email }: { email: string }) { + fetch('https://openadapt.ai/form.html', { + method: 'POST', + mode: 'no-cors', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ email, 'form-name': 'email', 'bot-field': '' }).toString(), + }).then(() => { + onboardingForm.reset(); + onClose(); + }); + } + + + useEffect(() => { + fetchOnboardingStatus().then(setShowOnboardingModal); + }, []); + + return ( + +

Let's get started with a quick onboarding process.

+ +
+ + + +
+ Register for updates (we promise not to spam) + + + + Book a call with us + + to discuss how OpenAdapt can help your team + +
+ ) +} diff --git a/openadapt/app/tray.py b/openadapt/app/tray.py index 1f7e52b55..67029d67a 100644 --- a/openadapt/app/tray.py +++ b/openadapt/app/tray.py @@ -128,10 +128,6 @@ def __init__(self) -> None: # self.app_action.triggered.connect(self.show_app) # self.menu.addAction(self.app_action) - self.dashboard_action = TrackedQAction("Launch Dashboard") - self.dashboard_action.triggered.connect(self.launch_dashboard) - self.menu.addAction(self.dashboard_action) - self.quit = TrackedQAction("Quit") def _quit() -> None: @@ -163,6 +159,8 @@ def _quit() -> None: # for storing toasts that should be manually removed self.sticky_toasts = {} + self.launch_dashboard() + def handle_recording_signal( self, notifier: QSocketNotifier, @@ -474,7 +472,6 @@ def launch_dashboard(self) -> None: self.dashboard_thread.join() self.dashboard_thread = run_dashboard() self.dashboard_thread.start() - self.dashboard_action.setText("Reload dashboard") def run(self) -> None: """Run the system tray icon.""" diff --git a/openadapt/config.defaults.json b/openadapt/config.defaults.json index 15c9840ac..17d36962c 100644 --- a/openadapt/config.defaults.json +++ b/openadapt/config.defaults.json @@ -83,5 +83,6 @@ "SPACY_MODEL_NAME": "en_core_web_trf", "DASHBOARD_CLIENT_PORT": 5173, "DASHBOARD_SERVER_PORT": 8080, - "UNIQUE_USER_ID": "" + "UNIQUE_USER_ID": "", + "SHOW_ONBOARDING_MODAL": true } diff --git a/openadapt/config.py b/openadapt/config.py index d18465e79..189f7cf44 100644 --- a/openadapt/config.py +++ b/openadapt/config.py @@ -227,6 +227,7 @@ def validate_scrub_fill_color(cls, v: Union[str, int]) -> int: # noqa: ANN102 SOM_SERVER_URL: str = "" UNIQUE_USER_ID: str = "" + SHOW_ONBOARDING_MODAL: bool = True class Adapter(str, Enum): """Adapter for the completions API.""" @@ -289,6 +290,7 @@ def __setattr__(self, key: str, value: Any) -> None: ], "general": [ "UNIQUE_USER_ID", + "SHOW_ONBOARDING_MODAL", ], } From 9d1ba66828d4bb219b1e41a9684513284e3c11f9 Mon Sep 17 00:00:00 2001 From: Shohan Dutta Roy Date: Fri, 14 Jun 2024 17:27:14 +0530 Subject: [PATCH 2/6] feat: Overhaul onboarding into a multistep process --- .../dashboard/components/Onboarding/index.tsx | 69 +++++++++---------- .../components/Onboarding/steps/BookACall.tsx | 19 +++++ .../Onboarding/steps/CompleteOnboarding.tsx | 17 +++++ .../Onboarding/steps/RegisterForUpdates.tsx | 48 +++++++++++++ .../components/Onboarding/steps/Tutorial.tsx | 12 ++++ 5 files changed, 128 insertions(+), 37 deletions(-) create mode 100644 openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx create mode 100644 openadapt/app/dashboard/components/Onboarding/steps/CompleteOnboarding.tsx create mode 100644 openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx create mode 100644 openadapt/app/dashboard/components/Onboarding/steps/Tutorial.tsx diff --git a/openadapt/app/dashboard/components/Onboarding/index.tsx b/openadapt/app/dashboard/components/Onboarding/index.tsx index 917fad120..2b8319bc7 100644 --- a/openadapt/app/dashboard/components/Onboarding/index.tsx +++ b/openadapt/app/dashboard/components/Onboarding/index.tsx @@ -1,18 +1,20 @@ 'use client'; import { get } from '@/api'; -import { Button, Checkbox, Divider, Grid, Modal, Stack, Text, TextInput } from '@mantine/core'; +import { Button, Checkbox, Divider, Grid, Group, Modal, Stack, Stepper, Text, TextInput } from '@mantine/core'; import { useForm } from '@mantine/form'; import Link from 'next/link'; import React, { useEffect, useState } from 'react' +import { Tutorial } from './steps/Tutorial'; +import { RegisterForUpdates } from './steps/RegisterForUpdates'; +import { BookACall } from './steps/BookACall'; +import { CompleteOnboarding } from './steps/CompleteOnboarding'; export const Onboarding = () => { const [showOnboardingModal, setShowOnboardingModal] = useState(false); - const onboardingForm = useForm({ - initialValues: { - email: '', - }, - }); + const [active, setActive] = useState(1); + const nextStep = () => setActive((current) => (current < 3 ? current + 1 : current)); + const prevStep = () => setActive((current) => (current > 0 ? current - 1 : current)); async function fetchOnboardingStatus() { const resp = await get<{ SHOW_ONBOARDING_MODAL: boolean }>('/api/settings?category=general', { @@ -21,7 +23,7 @@ export const Onboarding = () => { return resp.SHOW_ONBOARDING_MODAL; } - function onClose() { + function completeOnboarding() { fetch('/api/settings', { method: 'POST', headers: { @@ -31,42 +33,35 @@ export const Onboarding = () => { }).then(() => setShowOnboardingModal(false)); } - function onSubmit({ email }: { email: string }) { - fetch('https://openadapt.ai/form.html', { - method: 'POST', - mode: 'no-cors', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: new URLSearchParams({ email, 'form-name': 'email', 'bot-field': '' }).toString(), - }).then(() => { - onboardingForm.reset(); - onClose(); - }); - } - useEffect(() => { fetchOnboardingStatus().then(setShowOnboardingModal); }, []); return ( - -

Let's get started with a quick onboarding process.

- -
- - - -
- Register for updates (we promise not to spam) - - - - Book a call with us - - to discuss how OpenAdapt can help your team - + + + + + + + + + + + + + + + + {active < 3 && ( + + + + + )} ) } diff --git a/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx b/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx new file mode 100644 index 000000000..ebc8697b3 --- /dev/null +++ b/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx @@ -0,0 +1,19 @@ +import { Box, Text } from '@mantine/core' +import { IconCalendarCheck } from '@tabler/icons-react' +import Link from 'next/link' +import React from 'react' + +export const BookACall = () => { + return ( + + + + + Book a call with us + +
+ to discuss how OpenAdapt can help your team +
+
+ ) +} diff --git a/openadapt/app/dashboard/components/Onboarding/steps/CompleteOnboarding.tsx b/openadapt/app/dashboard/components/Onboarding/steps/CompleteOnboarding.tsx new file mode 100644 index 000000000..1e8a0bbcd --- /dev/null +++ b/openadapt/app/dashboard/components/Onboarding/steps/CompleteOnboarding.tsx @@ -0,0 +1,17 @@ +import { Button, Text } from '@mantine/core' +import React from 'react' + +type Props = { + completeOnboarding: () => void +} + +export const CompleteOnboarding = ({ + completeOnboarding +}: Props) => { + return ( + + Thanks for completing the onboarding process! You can always access these steps from the onboarding section in the sidebar. + + + ) +} diff --git a/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx b/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx new file mode 100644 index 000000000..600e5cb79 --- /dev/null +++ b/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx @@ -0,0 +1,48 @@ +import { Box, Button, Stack, Text, TextInput } from '@mantine/core' +import { isNotEmpty, useForm } from '@mantine/form' +import React from 'react' + +export const RegisterForUpdates = () => { + const onboardingForm = useForm({ + initialValues: { + email: '', + }, + validate: { + email: isNotEmpty('Email is required'), + } + }) + function onSubmit({ email }: { email: string }) { + fetch('https://openadapt.ai/form.html', { + method: 'POST', + mode: 'no-cors', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + email, + 'form-name': 'email', + 'bot-field': '', + }).toString(), + }).then(() => { + onboardingForm.reset() + }) + } + return ( + + +
+ + + +
+
+ ) +} diff --git a/openadapt/app/dashboard/components/Onboarding/steps/Tutorial.tsx b/openadapt/app/dashboard/components/Onboarding/steps/Tutorial.tsx new file mode 100644 index 000000000..01ba65c59 --- /dev/null +++ b/openadapt/app/dashboard/components/Onboarding/steps/Tutorial.tsx @@ -0,0 +1,12 @@ +import { Box } from '@mantine/core' +import React from 'react' + +export const Tutorial = () => { + return ( + + + + ) +} From 9cb58dd2b3aba59e42b1c27c4a3c4b2607d68019 Mon Sep 17 00:00:00 2001 From: Shohan Dutta Roy Date: Fri, 14 Jun 2024 17:52:08 +0530 Subject: [PATCH 3/6] docs: Update README.md with usage of the entrypoint module --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index eb41d1260..305dec99d 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,14 @@ Using python3.10 (3.10.13) Notice the environment prefix `(openadapt-py3.10)`. +### Tray +Run the following command to start the system tray icon and launch the web dashboard: + +``` +python -m openadapt.entrypoint +``` +This command will print the config, update the database to the latest migration, start the system tray icon and launch the web dashboard. + ### Record Create a new recording by running the following command: From a8db2c96f76b49f5635d41c006ec952cb96d8f53 Mon Sep 17 00:00:00 2001 From: Shohan Dutta Roy Date: Fri, 14 Jun 2024 21:05:56 +0530 Subject: [PATCH 4/6] refactor: Remove steppers and move all steps to a single page --- .../dashboard/components/Onboarding/index.tsx | 35 +++++-------------- .../components/Onboarding/steps/BookACall.tsx | 5 +-- .../Onboarding/steps/CompleteOnboarding.tsx | 17 --------- .../Onboarding/steps/RegisterForUpdates.tsx | 9 +++-- .../components/Onboarding/steps/Tutorial.tsx | 2 +- 5 files changed, 17 insertions(+), 51 deletions(-) delete mode 100644 openadapt/app/dashboard/components/Onboarding/steps/CompleteOnboarding.tsx diff --git a/openadapt/app/dashboard/components/Onboarding/index.tsx b/openadapt/app/dashboard/components/Onboarding/index.tsx index 2b8319bc7..5ef36b6bd 100644 --- a/openadapt/app/dashboard/components/Onboarding/index.tsx +++ b/openadapt/app/dashboard/components/Onboarding/index.tsx @@ -1,20 +1,14 @@ 'use client'; import { get } from '@/api'; -import { Button, Checkbox, Divider, Grid, Group, Modal, Stack, Stepper, Text, TextInput } from '@mantine/core'; -import { useForm } from '@mantine/form'; -import Link from 'next/link'; +import { Box, Divider, Modal } from '@mantine/core'; import React, { useEffect, useState } from 'react' import { Tutorial } from './steps/Tutorial'; import { RegisterForUpdates } from './steps/RegisterForUpdates'; import { BookACall } from './steps/BookACall'; -import { CompleteOnboarding } from './steps/CompleteOnboarding'; export const Onboarding = () => { const [showOnboardingModal, setShowOnboardingModal] = useState(false); - const [active, setActive] = useState(1); - const nextStep = () => setActive((current) => (current < 3 ? current + 1 : current)); - const prevStep = () => setActive((current) => (current > 0 ? current - 1 : current)); async function fetchOnboardingStatus() { const resp = await get<{ SHOW_ONBOARDING_MODAL: boolean }>('/api/settings?category=general', { @@ -42,26 +36,13 @@ export const Onboarding = () => { - - - - - - - - - - - - - - - {active < 3 && ( - - - - - )} + + + + + + + ) } diff --git a/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx b/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx index ebc8697b3..a7fb4d175 100644 --- a/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx +++ b/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx @@ -1,17 +1,14 @@ import { Box, Text } from '@mantine/core' -import { IconCalendarCheck } from '@tabler/icons-react' import Link from 'next/link' import React from 'react' export const BookACall = () => { return ( - - + Book a call with us -
to discuss how OpenAdapt can help your team
diff --git a/openadapt/app/dashboard/components/Onboarding/steps/CompleteOnboarding.tsx b/openadapt/app/dashboard/components/Onboarding/steps/CompleteOnboarding.tsx deleted file mode 100644 index 1e8a0bbcd..000000000 --- a/openadapt/app/dashboard/components/Onboarding/steps/CompleteOnboarding.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Button, Text } from '@mantine/core' -import React from 'react' - -type Props = { - completeOnboarding: () => void -} - -export const CompleteOnboarding = ({ - completeOnboarding -}: Props) => { - return ( - - Thanks for completing the onboarding process! You can always access these steps from the onboarding section in the sidebar. - - - ) -} diff --git a/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx b/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx index 600e5cb79..15bfabcb9 100644 --- a/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx +++ b/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx @@ -1,5 +1,6 @@ import { Box, Button, Stack, Text, TextInput } from '@mantine/core' import { isNotEmpty, useForm } from '@mantine/form' +import { notifications } from '@mantine/notifications' import React from 'react' export const RegisterForUpdates = () => { @@ -24,11 +25,15 @@ export const RegisterForUpdates = () => { 'bot-field': '', }).toString(), }).then(() => { - onboardingForm.reset() + notifications.show({ + title: 'Thank you!', + message: 'You have been registered for updates', + color: 'green', + }) }) } return ( - +
{ return ( - From 62e0df005061ad8cc9baedc53491311214501595 Mon Sep 17 00:00:00 2001 From: Shohan Dutta Roy Date: Tue, 18 Jun 2024 16:15:26 +0530 Subject: [PATCH 5/6] feat: Move onboarding to a separate page and add bounty card --- openadapt/app/dashboard/app/layout.tsx | 7 +- .../app/dashboard/app/onboarding/page.tsx | 16 +++++ openadapt/app/dashboard/app/routes.ts | 4 ++ .../components/Onboarding/Redirect.tsx | 30 +++++++++ .../dashboard/components/Onboarding/index.tsx | 48 -------------- .../components/Onboarding/steps/BookACall.tsx | 4 +- .../Onboarding/steps/RegisterForUpdates.tsx | 5 +- .../components/Onboarding/steps/Tutorial.tsx | 58 ++++++++++++++-- openadapt/app/dashboard/package-lock.json | 66 +++++++++++++++++++ openadapt/app/dashboard/package.json | 1 + openadapt/config.defaults.json | 2 +- openadapt/config.py | 4 +- 12 files changed, 181 insertions(+), 64 deletions(-) create mode 100644 openadapt/app/dashboard/app/onboarding/page.tsx create mode 100644 openadapt/app/dashboard/components/Onboarding/Redirect.tsx delete mode 100644 openadapt/app/dashboard/components/Onboarding/index.tsx diff --git a/openadapt/app/dashboard/app/layout.tsx b/openadapt/app/dashboard/app/layout.tsx index 3dae85845..76f71a748 100644 --- a/openadapt/app/dashboard/app/layout.tsx +++ b/openadapt/app/dashboard/app/layout.tsx @@ -4,8 +4,7 @@ import { ColorSchemeScript, MantineProvider } from '@mantine/core' import { Notifications } from '@mantine/notifications'; import { Shell } from '@/components/Shell' import { CSPostHogProvider } from './providers'; -import { ModalsProvider } from '@mantine/modals'; -import { Onboarding } from '@/components/Onboarding'; +import { RedirectToOnboarding } from '@/components/Onboarding/Redirect'; export const metadata = { title: 'OpenAdapt.AI', @@ -25,12 +24,10 @@ export default function RootLayout({ - - + {children} - diff --git a/openadapt/app/dashboard/app/onboarding/page.tsx b/openadapt/app/dashboard/app/onboarding/page.tsx new file mode 100644 index 000000000..78872f1ac --- /dev/null +++ b/openadapt/app/dashboard/app/onboarding/page.tsx @@ -0,0 +1,16 @@ +import { BookACall } from "@/components/Onboarding/steps/BookACall"; +import { RegisterForUpdates } from "@/components/Onboarding/steps/RegisterForUpdates"; +import { Tutorial } from "@/components/Onboarding/steps/Tutorial"; +import { Box, Divider } from "@mantine/core"; + +export default function Onboarding() { + return ( + + + + + + + + ); +} diff --git a/openadapt/app/dashboard/app/routes.ts b/openadapt/app/dashboard/app/routes.ts index a8ef8f96d..b0ef5f0d0 100644 --- a/openadapt/app/dashboard/app/routes.ts +++ b/openadapt/app/dashboard/app/routes.ts @@ -15,5 +15,9 @@ export const routes: Route[] = [ { name: 'Scrubbing', path: '/scrubbing', + }, + { + name: 'Onboarding', + path: '/onboarding', } ] diff --git a/openadapt/app/dashboard/components/Onboarding/Redirect.tsx b/openadapt/app/dashboard/components/Onboarding/Redirect.tsx new file mode 100644 index 000000000..3ea03190d --- /dev/null +++ b/openadapt/app/dashboard/components/Onboarding/Redirect.tsx @@ -0,0 +1,30 @@ +'use client'; + +import { get } from "@/api"; +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; + + +async function fetchOnboardingStatus() { + const resp = await get<{ REDIRECT_TO_ONBOARDING: boolean }>('/api/settings?category=general', { + cache: 'no-store', + }) + return resp.REDIRECT_TO_ONBOARDING; +} + +export const RedirectToOnboarding = () => { + const [redirect, setRedirect] = useState(false); + const router = useRouter(); + + useEffect(() => { + fetchOnboardingStatus().then(setRedirect); + }, []); + + useEffect(() => { + if (redirect) { + router.push('/onboarding'); + } + }, [redirect]); + + return null; +} diff --git a/openadapt/app/dashboard/components/Onboarding/index.tsx b/openadapt/app/dashboard/components/Onboarding/index.tsx deleted file mode 100644 index 5ef36b6bd..000000000 --- a/openadapt/app/dashboard/components/Onboarding/index.tsx +++ /dev/null @@ -1,48 +0,0 @@ -'use client'; - -import { get } from '@/api'; -import { Box, Divider, Modal } from '@mantine/core'; -import React, { useEffect, useState } from 'react' -import { Tutorial } from './steps/Tutorial'; -import { RegisterForUpdates } from './steps/RegisterForUpdates'; -import { BookACall } from './steps/BookACall'; - -export const Onboarding = () => { - const [showOnboardingModal, setShowOnboardingModal] = useState(false); - - async function fetchOnboardingStatus() { - const resp = await get<{ SHOW_ONBOARDING_MODAL: boolean }>('/api/settings?category=general', { - cache: 'no-store', - }) - return resp.SHOW_ONBOARDING_MODAL; - } - - function completeOnboarding() { - fetch('/api/settings', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ SHOW_ONBOARDING_MODAL: false }), - }).then(() => setShowOnboardingModal(false)); - } - - - useEffect(() => { - fetchOnboardingStatus().then(setShowOnboardingModal); - }, []); - - return ( - - - - - - - - - - ) -} diff --git a/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx b/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx index a7fb4d175..05179d818 100644 --- a/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx +++ b/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx @@ -4,8 +4,8 @@ import React from 'react' export const BookACall = () => { return ( - - + + Book a call with us diff --git a/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx b/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx index 15bfabcb9..091e0763a 100644 --- a/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx +++ b/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx @@ -1,3 +1,6 @@ +'use client'; + + import { Box, Button, Stack, Text, TextInput } from '@mantine/core' import { isNotEmpty, useForm } from '@mantine/form' import { notifications } from '@mantine/notifications' @@ -33,7 +36,7 @@ export const RegisterForUpdates = () => { }) } return ( - + +
+
+ {props.bounty.reward_formatted} +
+
+ {props.bounty.task.repo_name}#{props.bounty.task.number} +
+
+ {props.bounty.task.title} +
+
+ + ); +} + +const featuredBountyId = 'clxi7tk210002l20aqlz58ram'; + +async function getFeaturedBounty() { + const bounty: Bounty = await algora.bounty.get.query({ id: featuredBountyId }); + return bounty; +} export const Tutorial = () => { + const [featuredBounty, setFeaturedBounty] = React.useState(null); + useEffect(() => { + getFeaturedBounty().then(setFeaturedBounty); + }, []); return ( - + + Welcome to OpenAdapt! Thank you for joining us on our mission to build open source desktop AI. Your feedback is extremely valuable! + + + To start, please watch the demonstration below. Then try it yourself! + + + If you'd like to contribute directly to our development, please consider the following open Bounties (no development experience required): + {featuredBounty && } + + ) } diff --git a/openadapt/app/dashboard/package-lock.json b/openadapt/app/dashboard/package-lock.json index 07ac7c00c..c939b78fc 100644 --- a/openadapt/app/dashboard/package-lock.json +++ b/openadapt/app/dashboard/package-lock.json @@ -8,6 +8,7 @@ "name": "nextjs-fastapi", "version": "0.1.0", "dependencies": { + "@algora/sdk": "^0.2.0", "@mantine/carousel": "7.7.1", "@mantine/core": "7.7.1", "@mantine/form": "7.7.1", @@ -35,6 +36,16 @@ "prettier": "^3.2.5" } }, + "node_modules/@algora/sdk": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@algora/sdk/-/sdk-0.2.0.tgz", + "integrity": "sha512-J8r9OqNGnnRGjX29w9jyRAIih40PIoY+18q7zI5RQHZgne0gSmhUZrvAXqejMSpi8WbYpYetA4mViuvoTT1AxQ==", + "dependencies": { + "@trpc/client": "^10.0.0", + "@trpc/server": "^10.0.0", + "superjson": "^1.9.1" + } + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -702,6 +713,25 @@ "react": ">= 16" } }, + "node_modules/@trpc/client": { + "version": "10.45.2", + "resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.45.2.tgz", + "integrity": "sha512-ykALM5kYWTLn1zYuUOZ2cPWlVfrXhc18HzBDyRhoPYN0jey4iQHEFSEowfnhg1RvYnrAVjNBgHNeSAXjrDbGwg==", + "funding": [ + "https://trpc.io/sponsor" + ], + "peerDependencies": { + "@trpc/server": "10.45.2" + } + }, + "node_modules/@trpc/server": { + "version": "10.45.2", + "resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.45.2.tgz", + "integrity": "sha512-wOrSThNNE4HUnuhJG6PfDRp4L2009KDVxsd+2VYH8ro6o/7/jwYZ8Uu5j+VaW+mOmc8EHerHzGcdbGNQSAUPgg==", + "funding": [ + "https://trpc.io/sponsor" + ] + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -1456,6 +1486,20 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3346,6 +3390,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -5097,6 +5152,17 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/superjson": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-1.13.3.tgz", + "integrity": "sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg==", + "dependencies": { + "copy-anything": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", diff --git a/openadapt/app/dashboard/package.json b/openadapt/app/dashboard/package.json index 92398a2f9..787ee08b8 100644 --- a/openadapt/app/dashboard/package.json +++ b/openadapt/app/dashboard/package.json @@ -15,6 +15,7 @@ "format": "prettier --write ." }, "dependencies": { + "@algora/sdk": "^0.2.0", "@mantine/carousel": "7.7.1", "@mantine/core": "7.7.1", "@mantine/form": "7.7.1", diff --git a/openadapt/config.defaults.json b/openadapt/config.defaults.json index 17d36962c..a74f15eb9 100644 --- a/openadapt/config.defaults.json +++ b/openadapt/config.defaults.json @@ -84,5 +84,5 @@ "DASHBOARD_CLIENT_PORT": 5173, "DASHBOARD_SERVER_PORT": 8080, "UNIQUE_USER_ID": "", - "SHOW_ONBOARDING_MODAL": true + "REDIRECT_TO_ONBOARDING": true } diff --git a/openadapt/config.py b/openadapt/config.py index 189f7cf44..742aeaa88 100644 --- a/openadapt/config.py +++ b/openadapt/config.py @@ -227,7 +227,7 @@ def validate_scrub_fill_color(cls, v: Union[str, int]) -> int: # noqa: ANN102 SOM_SERVER_URL: str = "" UNIQUE_USER_ID: str = "" - SHOW_ONBOARDING_MODAL: bool = True + REDIRECT_TO_ONBOARDING: bool = True class Adapter(str, Enum): """Adapter for the completions API.""" @@ -290,7 +290,7 @@ def __setattr__(self, key: str, value: Any) -> None: ], "general": [ "UNIQUE_USER_ID", - "SHOW_ONBOARDING_MODAL", + "REDIRECT_TO_ONBOARDING", ], } From 220ef9e3e21e4f15b89af17b8f3a6d0dcdf281e7 Mon Sep 17 00:00:00 2001 From: Shohan Dutta Roy Date: Wed, 19 Jun 2024 15:01:50 +0530 Subject: [PATCH 6/6] feat: Redirect to onboarding on launch, and move around content --- openadapt/app/dashboard/app/layout.tsx | 2 -- .../app/dashboard/app/onboarding/page.tsx | 4 +-- .../app/dashboard/app/recordings/page.tsx | 4 +-- .../components/Onboarding/Redirect.tsx | 30 ------------------- .../Onboarding/steps/RegisterForUpdates.tsx | 13 +++++++- .../components/Onboarding/steps/Tutorial.tsx | 4 +-- openadapt/app/dashboard/index.js | 8 +++-- openadapt/app/dashboard/run.py | 11 +++++-- 8 files changed, 32 insertions(+), 44 deletions(-) delete mode 100644 openadapt/app/dashboard/components/Onboarding/Redirect.tsx diff --git a/openadapt/app/dashboard/app/layout.tsx b/openadapt/app/dashboard/app/layout.tsx index 76f71a748..3cd56c206 100644 --- a/openadapt/app/dashboard/app/layout.tsx +++ b/openadapt/app/dashboard/app/layout.tsx @@ -4,7 +4,6 @@ import { ColorSchemeScript, MantineProvider } from '@mantine/core' import { Notifications } from '@mantine/notifications'; import { Shell } from '@/components/Shell' import { CSPostHogProvider } from './providers'; -import { RedirectToOnboarding } from '@/components/Onboarding/Redirect'; export const metadata = { title: 'OpenAdapt.AI', @@ -25,7 +24,6 @@ export default function RootLayout({ - {children} diff --git a/openadapt/app/dashboard/app/onboarding/page.tsx b/openadapt/app/dashboard/app/onboarding/page.tsx index 78872f1ac..d4a3ecdde 100644 --- a/openadapt/app/dashboard/app/onboarding/page.tsx +++ b/openadapt/app/dashboard/app/onboarding/page.tsx @@ -6,11 +6,11 @@ import { Box, Divider } from "@mantine/core"; export default function Onboarding() { return ( - - + + ); } diff --git a/openadapt/app/dashboard/app/recordings/page.tsx b/openadapt/app/dashboard/app/recordings/page.tsx index 901444f76..46e5f8361 100644 --- a/openadapt/app/dashboard/app/recordings/page.tsx +++ b/openadapt/app/dashboard/app/recordings/page.tsx @@ -50,7 +50,7 @@ export default function Recordings() { }, []); return ( - {recordingStatus === RecordingStatus.RECORDING && ( + {/* {recordingStatus === RecordingStatus.RECORDING && ( @@ -64,7 +64,7 @@ export default function Recordings() { - )} + )} */} diff --git a/openadapt/app/dashboard/components/Onboarding/Redirect.tsx b/openadapt/app/dashboard/components/Onboarding/Redirect.tsx deleted file mode 100644 index 3ea03190d..000000000 --- a/openadapt/app/dashboard/components/Onboarding/Redirect.tsx +++ /dev/null @@ -1,30 +0,0 @@ -'use client'; - -import { get } from "@/api"; -import { useRouter } from "next/navigation"; -import { useEffect, useState } from "react"; - - -async function fetchOnboardingStatus() { - const resp = await get<{ REDIRECT_TO_ONBOARDING: boolean }>('/api/settings?category=general', { - cache: 'no-store', - }) - return resp.REDIRECT_TO_ONBOARDING; -} - -export const RedirectToOnboarding = () => { - const [redirect, setRedirect] = useState(false); - const router = useRouter(); - - useEffect(() => { - fetchOnboardingStatus().then(setRedirect); - }, []); - - useEffect(() => { - if (redirect) { - router.push('/onboarding'); - } - }, [redirect]); - - return null; -} diff --git a/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx b/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx index 091e0763a..37470ecf5 100644 --- a/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx +++ b/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx @@ -4,7 +4,7 @@ import { Box, Button, Stack, Text, TextInput } from '@mantine/core' import { isNotEmpty, useForm } from '@mantine/form' import { notifications } from '@mantine/notifications' -import React from 'react' +import React, { useEffect } from 'react' export const RegisterForUpdates = () => { const onboardingForm = useForm({ @@ -15,6 +15,17 @@ export const RegisterForUpdates = () => { email: isNotEmpty('Email is required'), } }) + useEffect(() => { + fetch('/api/settings', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + REDIRECT_TO_ONBOARDING: false + }), + }) + }, []) function onSubmit({ email }: { email: string }) { fetch('https://openadapt.ai/form.html', { method: 'POST', diff --git a/openadapt/app/dashboard/components/Onboarding/steps/Tutorial.tsx b/openadapt/app/dashboard/components/Onboarding/steps/Tutorial.tsx index 03db644e5..eca662c92 100644 --- a/openadapt/app/dashboard/components/Onboarding/steps/Tutorial.tsx +++ b/openadapt/app/dashboard/components/Onboarding/steps/Tutorial.tsx @@ -48,13 +48,13 @@ export const Tutorial = () => { Welcome to OpenAdapt! Thank you for joining us on our mission to build open source desktop AI. Your feedback is extremely valuable!
- To start, please watch the demonstration below. Then try it yourself! + To start, please watch the demonstration below. Then try it yourself! If you have any issues, please submit a Github Issue. + If you'd like to contribute directly to our development, please consider the following open Bounties (no development experience required): {featuredBounty && } -
) } diff --git a/openadapt/app/dashboard/index.js b/openadapt/app/dashboard/index.js index b16703cc9..161d03c6d 100644 --- a/openadapt/app/dashboard/index.js +++ b/openadapt/app/dashboard/index.js @@ -17,7 +17,7 @@ const checkPort = (port) => { } // check if both ports are not being used -const { DASHBOARD_CLIENT_PORT, DASHBOARD_SERVER_PORT } = process.env +const { DASHBOARD_CLIENT_PORT, DASHBOARD_SERVER_PORT, REDIRECT_TO_ONBOARDING } = process.env Promise.all([checkPort(DASHBOARD_CLIENT_PORT), checkPort(DASHBOARD_SERVER_PORT)]) .then(([clientPort, serverPort]) => { if (clientPort !== DASHBOARD_CLIENT_PORT) { @@ -45,7 +45,11 @@ function spawnChildProcess() { // wait for 3 seconds before opening the browser setTimeout(() => { import('open').then(({ default: open }) => { - open(`http://localhost:${DASHBOARD_CLIENT_PORT}`) + let url = `http://localhost:${DASHBOARD_CLIENT_PORT}` + if (REDIRECT_TO_ONBOARDING === 'true') { + url += '/onboarding' + } + open(url) }) }, 3000) }) diff --git a/openadapt/app/dashboard/run.py b/openadapt/app/dashboard/run.py index e6fd43186..87839b1f1 100644 --- a/openadapt/app/dashboard/run.py +++ b/openadapt/app/dashboard/run.py @@ -25,9 +25,11 @@ def run() -> Thread: def run_client() -> subprocess.Popen: """The entry point for the thread that runs the dashboard client.""" if is_running_from_executable(): - webbrowser.open( - f"http://localhost:{config.DASHBOARD_SERVER_PORT}/recordings" - ) + if config.REDIRECT_TO_ONBOARDING: + url = f"http://localhost:{config.DASHBOARD_SERVER_PORT}/onboarding" + else: + url = f"http://localhost:{config.DASHBOARD_SERVER_PORT}" + webbrowser.open(url) run_app() return @@ -41,6 +43,9 @@ def run_client() -> subprocess.Popen: "DASHBOARD_SERVER_PORT": str(config.DASHBOARD_SERVER_PORT), "NEXT_PUBLIC_POSTHOG_HOST": POSTHOG_HOST, "NEXT_PUBLIC_POSTHOG_PUBLIC_KEY": POSTHOG_PUBLIC_KEY, + "REDIRECT_TO_ONBOARDING": ( + "true" if config.REDIRECT_TO_ONBOARDING else "false" + ), "NEXT_PUBLIC_MODE": ( "production" if is_running_from_executable() else "development" ),