import { Code, Table2 } from 'lucide-react' import { useRouter } from 'next/router' import { useCallback, useMemo, useState } from 'react' import { useParams } from 'common' import { FRAMEWORKS } from 'components/interfaces/Connect/Connect.constants' import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { BASE_PATH } from 'lib/constants' import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state' import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state' import { Button, Card, CardContent, ToggleGroup, ToggleGroupItem } from 'ui' import { FrameworkSelector } from './FrameworkSelector' import { GettingStarted } from './GettingStarted' import { GettingStartedAction, GettingStartedState, GettingStartedStep, } from './GettingStarted.types' import { DEFAULT_FRAMEWORK_KEY, getCodeWorkflowSteps, getNoCodeWorkflowSteps, } from './GettingStarted.utils' import { useGettingStartedProgress } from './useGettingStartedProgress' interface GettingStartedSectionProps { value: GettingStartedState onChange: (v: GettingStartedState) => void } export function GettingStartedSection({ value, onChange }: GettingStartedSectionProps) { const router = useRouter() const { ref } = useParams() const { data: project } = useSelectedProjectQuery() const { data: organization } = useSelectedOrganizationQuery() const { mutate: sendEvent } = useSendEventMutation() const aiSnap = useAiAssistantStateSnapshot() const { openSidebar } = useSidebarManagerSnapshot() const [selectedFramework, setSelectedFramework] = useState(DEFAULT_FRAMEWORK_KEY) const workflow: 'no-code' | 'code' | null = value === 'code' || value === 'no-code' ? value : null const [previousWorkflow, setPreviousWorkflow] = useState<'no-code' | 'code' | null>(null) const statuses = useGettingStartedProgress() const openAiChat = useCallback( (name: string, initialInput: string) => { openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) aiSnap.newChat({ name, initialInput }) }, [aiSnap, openSidebar] ) const connectPresetLinks = useMemo(() => { const basePath = router.asPath.split('?')[0] const parent = FRAMEWORKS.find((f) => f.key === selectedFramework) if (!parent) { return [ { label: 'Connect', href: `${basePath}?showConnect=true&connectTab=frameworks`, }, ] } let using: string | undefined let withKey: string | undefined if (parent.children && parent.children.length > 0) { // prefer App Router for Nextjs by default if (parent.key === 'nextjs') { const appChild = parent.children.find((c) => c.key === 'app') || parent.children[0] using = appChild?.key withKey = appChild?.children?.[0]?.key } else { using = parent.children[0]?.key withKey = parent.children[0]?.children?.[0]?.key } } const qs = new URLSearchParams({ showConnect: 'true', connectTab: 'frameworks', framework: parent.key, }) if (using) qs.set('using', using) if (withKey) qs.set('with', withKey) return [ { label: 'Connect', href: `${basePath}?${qs.toString()}`, }, ] }, [router.asPath, selectedFramework]) const connectActions: GettingStartedAction[] = useMemo(() => { const selector: GettingStartedAction = { label: 'Framework selector', component: ( ), } const linkActions: GettingStartedAction[] = connectPresetLinks.map((lnk) => ({ label: 'Connect', href: lnk.href, variant: 'primary', })) return [selector, ...linkActions] }, [connectPresetLinks, selectedFramework]) const codeSteps: GettingStartedStep[] = useMemo( () => getCodeWorkflowSteps({ ref, openAiChat, connectActions, statuses, }), [connectActions, openAiChat, ref, statuses] ) const noCodeSteps: GettingStartedStep[] = useMemo( () => getNoCodeWorkflowSteps({ ref, openAiChat, connectActions, statuses, }), [connectActions, openAiChat, ref, statuses] ) const steps = workflow === 'code' ? codeSteps : workflow === 'no-code' ? noCodeSteps : [] return (

Getting started

{ if (v) { const newWorkflow = v as 'no-code' | 'code' setPreviousWorkflow(workflow) onChange(newWorkflow) sendEvent({ action: 'home_getting_started_workflow_clicked', properties: { workflow: newWorkflow === 'no-code' ? 'no_code' : 'code', is_switch: previousWorkflow !== null, }, groups: { project: project?.ref || '', organization: organization?.slug || '', }, }) } }} > No-code Code
{steps.length === 0 ? (
Supabase Grafana Supabase Grafana

Choose a preferred workflow

With Supabase, you have the flexibility to adopt a workflow that works for you. You can do everything via the dashboard, or manage your entire project within your own codebase.

) : ( { if (workflow) { sendEvent({ action: 'home_getting_started_step_clicked', properties: { workflow: workflow === 'no-code' ? 'no_code' : 'code', step_number: stepIndex + 1, step_title: stepTitle, action_type: actionType, was_completed: wasCompleted, }, groups: { project: project?.ref || '', organization: organization?.slug || '', }, }) } }} /> )}
) }