Files
supabase/apps/studio/components/interfaces/Explorer/ExplorerOnboarding.tsx
Saxon FletcherandClaude Opus 5 252f69e451 chore(studio): refine Explorer sidebar, onboarding, and notebooks (#50555)
## Summary

A round of small Explorer refinements.

**Sidebar**
- Adds a **Run SQL** row (with a `+` icon) above Notebooks in the
Explorer sidebar; opens a new query tab.

**Assistant**
- Assistant query cells now have the same **Save** dropdown as query
tabs (add to an existing notebook or create a new one). It shows only
when Explorer is enabled, and not while the query is still streaming.
- `SaveQueryDropdown` takes an optional `source`, so logs queries are
saved as log cells (keeping their time range) instead of database cells.
This also fixes saving logs queries from query tabs.
- The "Drafting notebook..." notice (and the notebook loading/status
rows) now span the full message width; `delete_notebook` parts use the
wide layout like create/update.

**Onboarding**
- Replaces the single page with a four-step walkthrough: Welcome to
Explorer (with a **Preview** badge), Run SQL, Notebooks, and Chat with
your project. Each step has an icon, heading, and short description,
with step dots and **Skip** / **Back** / **Next** buttons; the last step
ends with **Continue to Explorer**.
- Removes the "Choose how Explorer opens" choice (still available in
Account preferences) and the collapsible "Learn more" section. Skipping
or finishing still respects the saved startup preference.
- Deletes `ExplorerOnboardingLearnMore`, `ExplorerHomePreference`, and
`ExplorerHomePreview`, which were only used by onboarding.

**Notebooks**
- Query cells use the same max width as markdown cells (`48rem`, was
`72rem`).
- "Add query cell" / "Add markdown cell" are now **Add query** / **Add
markdown** everywhere; the buttons at the bottom of a notebook are
larger (34px, 18px icons).

## Test plan

- [ ] Explorer sidebar: **Run SQL** opens a new query tab
- [ ] Assistant: generate SQL, use **Save** to add it to a new and an
existing notebook; repeat with a logs query and confirm a log cell is
created
- [ ] Assistant: ask for a notebook and confirm the drafting notice is
full width
- [ ] Clear `hasCompletedOnboarding` in Explorer preferences and step
through onboarding (Next / Back / Skip); finishing or skipping respects
the startup preference set in Account preferences
- [ ] Notebook: query cells line up with markdown cell width; bottom add
buttons are larger


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
  - Added a **Run SQL** shortcut to Explorer navigation.
- Assistant query results can now be saved to notebooks, including log
queries.

- **Improvements**
- Updated Explorer onboarding with guided steps, progress navigation,
and visual previews.
  - Shortened Explorer action labels and refined control sizing.
- Reduced notebook query layout width and adjusted assistant notebook
displays.

- **Changes**
- Removed the Explorer startup preference selector and onboarding “Learn
more” section.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 14:38:29 +08:00

123 lines
4.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ArrowRight } from 'lucide-react'
import { useState, type ComponentType } from 'react'
import { Badge, Button, cn } from 'ui'
import {
ChatWireframe,
NotebooksWireframe,
RunSqlWireframe,
WelcomeWireframe,
} from './ExplorerOnboardingWireframes'
import { useExplorerPreferences } from '@/components/interfaces/Account/Preferences/useExplorerPreferences'
const ONBOARDING_STEPS: Array<{
Wireframe: ComponentType
title: string
description: string
isPreview?: boolean
}> = [
{
Wireframe: WelcomeWireframe,
title: 'Welcome to Explorer',
description:
'Interact with your database and logs in one place. Run SQL, save your work to notebooks, and chat with Assistant.',
isPreview: true,
},
{
Wireframe: RunSqlWireframe,
title: 'Run SQL',
description:
'Run any SQL on your database, just like in the SQL Editor. You can also query your logs and chart the results.',
},
{
Wireframe: NotebooksWireframe,
title: 'Notebooks',
description:
'Snippets have evolved into notebooks. Combine multiple queries with markdown notes for you, your team, or Assistant to run later.',
},
{
Wireframe: ChatWireframe,
title: 'Chat with your project',
description:
'Ask Assistant to write queries, explain results, or build notebooks for you. Your organization’s AI settings control what it can access.',
},
]
export const ExplorerOnboarding = () => {
const { completeOnboarding, isReady } = useExplorerPreferences()
const [stepIndex, setStepIndex] = useState(0)
const step = ONBOARDING_STEPS[stepIndex]
const isFirstStep = stepIndex === 0
const isLastStep = stepIndex === ONBOARDING_STEPS.length - 1
const { Wireframe } = step
return (
<div className="flex h-full min-h-0 flex-col items-center overflow-y-auto bg-surface-100 px-6">
<div className="my-auto w-full max-w-xl shrink-0 space-y-8 py-12">
<div aria-live="polite" className="space-y-6">
<Wireframe />
<div className="min-h-24 space-y-2">
<div className="flex items-center gap-2">
<h1 className="heading-section">{step.title}</h1>
{step.isPreview && <Badge variant="default">Preview</Badge>}
</div>
<p className="text-base leading-relaxed text-foreground-light">{step.description}</p>
</div>
</div>
<div className="flex items-center justify-between gap-4">
<div className="flex items-center gap-1.5">
<span className="sr-only">
Step {stepIndex + 1} of {ONBOARDING_STEPS.length}
</span>
{ONBOARDING_STEPS.map(({ title }, index) => (
<span
key={title}
aria-hidden="true"
className={cn(
'h-1.5 rounded-full transition-all',
index === stepIndex ? 'w-4 bg-foreground' : 'w-1.5 bg-border-stronger'
)}
/>
))}
</div>
<div className="flex items-center gap-2">
{!isLastStep && (
<Button type="button" variant="text" onClick={completeOnboarding} disabled={!isReady}>
Skip
</Button>
)}
{!isFirstStep && (
<Button type="button" variant="default" onClick={() => setStepIndex(stepIndex - 1)}>
Back
</Button>
)}
{isLastStep ? (
<Button
type="button"
variant="primary"
iconRight={<ArrowRight />}
onClick={completeOnboarding}
disabled={!isReady}
>
Continue to Explorer
</Button>
) : (
<Button
type="button"
variant="primary"
iconRight={<ArrowRight />}
onClick={() => setStepIndex(stepIndex + 1)}
>
Next
</Button>
)}
</div>
</div>
</div>
</div>
)
}