From 9106d95fccfba4e2dda7fe4d6273251176cb097f Mon Sep 17 00:00:00 2001 From: Abhinaysai Kamineni Date: Thu, 25 Jun 2026 12:04:40 -0400 Subject: [PATCH 1/2] Improve first-run onboarding and Connection workspace UX. Add a four-step onboarding flow, persist settings under cortex_settings_v2, surface workspace presets and live-demo context on Home, and wire replay tour. Co-authored-by: Cursor --- .../components/onboarding/OnboardingModal.tsx | 175 ++++++++++++++---- frontend/src/lib/onboarding.ts | 22 ++- frontend/src/lib/settings.ts | 54 ++++++ frontend/src/views/HomeView.tsx | 153 ++++++++------- 4 files changed, 300 insertions(+), 104 deletions(-) create mode 100644 frontend/src/lib/settings.ts diff --git a/frontend/src/components/onboarding/OnboardingModal.tsx b/frontend/src/components/onboarding/OnboardingModal.tsx index f4a0ac4..4b432d8 100644 --- a/frontend/src/components/onboarding/OnboardingModal.tsx +++ b/frontend/src/components/onboarding/OnboardingModal.tsx @@ -1,69 +1,174 @@ import { useState } from "react"; import { markOnboardingComplete } from "../../lib/onboarding"; +import { useApp } from "../../context/AppContext"; +import { IconSpark } from "../ui/icons"; type Props = { onComplete: () => void; onOpenCopilot: () => void; + onFinishAsk: (workspace: string, query: string) => void; }; -const STEPS = [ - { - title: "Your organization's living memory", - body: "Cortex captures decisions — not documents — from Slack, GitHub, Jira, and more. Ask natural questions and get answers with who decided, why, and what's affected.", - icon: "◈", - }, - { - title: "Ask in plain language", - body: 'Try questions like "Why did we choose CockroachDB for payments?" or "What affects checkout?" Cortex searches structured memory, not scattered threads.', - icon: "?", - }, - { - title: "Meet Assist", - body: "Cortex Assist guides you, runs searches, and explains results. Use the memory map to see how people, systems, and decisions connect over time.", - icon: "✦", - }, +const WORKSPACE_PRESETS = [ + { id: "local-dev", label: "Demo workspace", hint: "Pre-seeded decisions for demos" }, + { id: "oss-tiangolo-fastapi", label: "OSS: FastAPI", hint: "Open-source graph import" }, + { id: "oss-adr", label: "OSS: ADRs", hint: "Architecture decision records" }, ] as const; -export function OnboardingModal({ onComplete, onOpenCopilot }: Props) { +const DEMO_QUERY = "Why CockroachDB for payments?"; + +export function OnboardingModal({ onComplete, onOpenCopilot, onFinishAsk }: Props) { + const { setWorkspaceId, apiKey, setApiKey, saveApiKey } = useApp(); const [step, setStep] = useState(0); - const current = STEPS[step]; - const isLast = step === STEPS.length - 1; + const [workspace, setWorkspace] = useState("local-dev"); + const isLast = step === 3; - function finish() { - markOnboardingComplete(); + function finishToAsk(): void { + markOnboardingComplete(workspace); + setWorkspaceId(workspace); onComplete(); - if (isLast) onOpenCopilot(); + onFinishAsk(workspace, DEMO_QUERY); + } + + function finishToAssist(): void { + markOnboardingComplete(workspace); + setWorkspaceId(workspace); + onComplete(); + onOpenCopilot(); } return ( -
+
- {STEPS.map((_, i) => ( + {[0, 1, 2, 3].map((i) => ( ))}
- - {current.icon} - -

- {current.title} -

-

{current.body}

+ + {step === 0 ? ( + <> + + ◈ + +

+ Your organization's living memory +

+

+ Cortex captures decisions — not documents — from Slack, GitHub, Jira, + and more. Ask natural questions and get answers with who decided, why, and what's + affected. +

+ + ) : null} + + {step === 1 ? ( + <> +

+ Choose a workspace +

+

+ Workspaces isolate organizational memory. Start with the demo workspace or pick an OSS + preset. +

+
+ {WORKSPACE_PRESETS.map((w) => ( + + ))} +
+ + ) : null} + + {step === 2 ? ( + <> +

+ Try a demo search +

+

+ We'll open Search with a sample question so you can see trust scores, coverage, and + decision stories in seconds. +

+
{DEMO_QUERY}
+ + ) : null} + + {step === 3 ? ( + <> +

+ Connection (optional) +

+

+ The public demo works without a key. If your deployment requires authentication, add + your API key now — you can always change it under Connection later. +

+ + setApiKey(e.target.value)} + placeholder="Optional" + autoComplete="off" + /> + + ) : null} +