GettingStarted() — supabase Function Reference
Architecture documentation for the GettingStarted() function in GettingStarted.tsx from the supabase codebase.
Entity Profile
Dependency Diagram
graph TD 0a2528cb_2bc9_b172_9b0c_c1f066605d75["GettingStarted()"] 3dd309c0_f8c6_e703_4eec_6d7aad0a13ef["getActionType()"] 0a2528cb_2bc9_b172_9b0c_c1f066605d75 -->|calls| 3dd309c0_f8c6_e703_4eec_6d7aad0a13ef style 0a2528cb_2bc9_b172_9b0c_c1f066605d75 fill:#6366f1,stroke:#818cf8,color:#fff
Relationship Graph
Source Code
apps/studio/components/interfaces/HomeNew/GettingStarted/GettingStarted.tsx lines 42–300
export function GettingStarted({ steps, onStepClick }: GettingStartedProps) {
const allStepsComplete = steps.length > 0 && steps.every((step) => step.status === 'complete')
const [activeStepKey, setActiveStepKey] = useState<string | null>(null)
useEffect(() => {
if (steps.length === 0) {
setActiveStepKey(null)
return
}
// Check if the current active step key is still valid in the new steps array
const isActiveStepValid = activeStepKey && steps.some((step) => step.key === activeStepKey)
// If no step is selected or the active step is no longer valid (e.g., after tab switch)
if (!isActiveStepValid) {
// If all steps are complete, don't select any step
if (allStepsComplete) {
setActiveStepKey(null)
} else {
// Select the first incomplete step, or the first step if all are complete
const firstIncompleteStep = steps.find((step) => step.status !== 'complete')
setActiveStepKey(firstIncompleteStep?.key ?? steps[0]?.key ?? null)
}
}
}, [steps, allStepsComplete, activeStepKey])
const activeStep = activeStepKey ? steps.find((step) => step.key === activeStepKey) : null
const activeStepIndex = activeStep ? steps.findIndex((step) => step.key === activeStep.key) : -1
const previousStep = activeStepIndex > 0 ? steps[activeStepIndex - 1] : null
const nextStep =
activeStepIndex > -1 && activeStepIndex < steps.length - 1 ? steps[activeStepIndex + 1] : null
const handleSelectPrevious = () => {
if (previousStep) {
setActiveStepKey(previousStep.key)
}
}
const handleSelectNext = () => {
if (nextStep) {
setActiveStepKey(nextStep.key)
}
}
const showCongratulations = allStepsComplete && !activeStep
return (
<Card className="overflow-hidden @container">
<div className="flex flex-col @2xl:flex-row">
<aside className="hidden border-r @2xl:block @2xl:w-[calc(1/3*100%-16px)]">
<ol>
{steps.map((step, index) => {
const isActive = activeStep ? step.key === activeStep.key : false
const isComplete = step.status === 'complete'
return (
<li key={step.key} className="border-b last:border-b-0 truncate">
<Button
type="text"
onClick={() => setActiveStepKey(step.key)}
className={cn(
'pl-1 block justify-start w-full rounded-none h-auto text-left text-foreground-light',
isActive && 'bg-muted text-foreground'
)}
>
<div className="flex items-center gap-3 text-sm w-full">
<span
className={cn(
'text-xs shrink-0 font-mono text-foreground-light w-7 h-7 bg border flex items-center justify-center rounded-md'
)}
>
{isComplete ? (
<Check size={16} strokeWidth={1.5} className="text-brand-link" />
) : (
index + 1
)}
</span>
<span
className={cn(
'flex-1 block truncate',
isActive ? 'text-foreground' : 'group-hover:text-foreground',
isComplete && 'line-through'
)}
>
{step.title}
</span>
<ChevronRight
size={16}
strokeWidth={1.5}
className="text-foreground-lighter"
/>
</div>
</Button>
</li>
)
})}
</ol>
</aside>
<CardContent className="flex flex-1 flex-col gap-0 p-0 overflow-y-auto border-b-0">
{showCongratulations ? (
<div className="relative w-full flex-1 min-h-[100px] shrink-0 overflow-hidden bg-200 flex flex-col justify-end">
<div className="p-10">
<div className="w-8 h-8 rounded-md bg-brand/15 flex items-center justify-center shrink-0 mb-4">
<Check size={16} strokeWidth={1.5} className="text-brand-link" />
</div>
<div className="flex flex-row items-center gap-4 mb-1">
<h3>All steps complete</h3>
</div>
<p className="text-foreground-light max-w-prose mb-4 text-balance">
Drop into our Discord community to share your progress and learn from fellow
developers.
</p>
<Button
asChild
type="default"
icon={<IconDiscord size={14} />}
className="text-foreground-light hover:text-foreground"
>
<Link href={'https://discord.supabase.com/'} target="_blank">
Join our Discord
</Link>
</Button>
</div>
</div>
) : (
<>
<div className="flex items-center justify-between gap-2 border-b px-2 py-2 @2xl:hidden">
<span className="text-xs shrink-0 font-mono text-foreground-light w-7 h-7 bg border flex items-center justify-center rounded-md">
{activeStepIndex + 1}
</span>
<div className="flex items-center gap-2">
<Button
type="outline"
onClick={handleSelectPrevious}
disabled={!previousStep}
className="gap-2"
aria-label="Previous step"
>
<ChevronLeft size={16} strokeWidth={1.5} />
</Button>
<Button
type="outline"
onClick={handleSelectNext}
disabled={!nextStep}
className="gap-2"
aria-label="Next step"
>
<ChevronRight size={16} strokeWidth={1.5} />
</Button>
</div>
</div>
<div className="relative w-full flex-1 min-h-[100px] shrink-0 overflow-hidden">
{activeStep?.image ? (
<Image
className="w-full select-none invert dark:invert-0"
src={activeStep.image}
fill
objectFit="cover"
objectPosition="top"
alt={activeStep.title}
/>
) : (
<div className="absolute top-0 left-0 right-0 overflow-hidden">
<img
src={`${BASE_PATH}/img/reports/bg-grafana-dark.svg`}
alt="Supabase Grafana"
className="w-full h-full object-cover object-right hidden dark:block user-select-none"
/>
<img
src={`${BASE_PATH}/img/reports/bg-grafana-light.svg`}
alt="Supabase Grafana"
className="w-full h-full object-cover object-right dark:hidden user-select-none"
/>
</div>
)}
<div className="absolute bottom-0 left-0 right-0 h-16 bg-gradient-to-t from-background-surface-100 to-transparent" />
</div>
<div className="p-10">
{activeStep && (
<>
<div className="flex flex-row items-center gap-4 mb-1">
<h3>{activeStep.title}</h3>
<Badge
variant={activeStep.status === 'complete' ? 'success' : 'default'}
className="capitalize hidden @2xl:inline-flex"
>
{activeStep.status}
</Badge>
</div>
<p className="text-foreground-light max-w-prose mb-4 text-balance">
{activeStep.description}
</p>
<div className="mt-auto flex flex-wrap gap-2 pt-2">
{activeStep.actions.map((action, i) => {
if (action.component) {
return <div key={`${activeStep.key}-action-${i}`}>{action.component}</div>
}
const actionType = getActionType(action)
if (action.href) {
return (
<Button
asChild
key={`${activeStep.key}-action-${i}`}
type={action.variant ?? 'default'}
icon={action.icon}
className="text-foreground-light hover:text-foreground"
>
<Link
href={action.href}
onClick={() => {
onStepClick({
stepIndex: activeStepIndex,
stepTitle: activeStep.title,
actionType,
wasCompleted: activeStep.status === 'complete',
})
}}
>
{action.label}
</Link>
</Button>
)
}
return (
<Button
key={`${activeStep.key}-action-${i}`}
type={action.variant ?? 'default'}
icon={action.icon}
onClick={() => {
action.onClick?.()
onStepClick({
stepIndex: activeStepIndex,
stepTitle: activeStep.title,
actionType,
wasCompleted: activeStep.status === 'complete',
})
}}
className="text-foreground-light hover:text-foreground"
>
{action.label}
</Button>
)
})}
</div>
</>
)}
</div>
</>
)}
</CardContent>
</div>
</Card>
)
}
Domain
Subdomains
Calls
Source
Frequently Asked Questions
What does GettingStarted() do?
GettingStarted() is a function in the supabase codebase.
What does GettingStarted() call?
GettingStarted() calls 1 function(s): getActionType.
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free