ruvector/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.tsx
rUv 814f595995 feat(studio): Add complete RuVector Studio application
Major additions:
- Complete Next.js studio application with 1600+ components
- Docker support (Dockerfile.combined, docker-compose.yml)
- GCP deployment documentation and benchmarks
- SQL benchmark scripts for performance testing
- Sentry integration for monitoring
- Comprehensive test suite and mocks

Studio features:
- Dashboard and admin interfaces
- Data visualization components
- Authentication and user management
- API integration with RuVector backend
- Static data and public assets

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:04:48 +00:00

167 lines
5.8 KiB
TypeScript

import { useParams } from 'common'
import { useState } from 'react'
import { DocsButton } from 'components/ui/DocsButton'
import { useEdgeFunctionsQuery } from 'data/edge-functions/edge-functions-query'
import { useOpenAPISpecQuery } from 'data/open-api/api-spec-query'
import { useBucketsQuery } from 'data/storage/buckets-query'
import { DOCS_URL } from 'lib/constants'
import { ChevronLeft, Code } from 'lucide-react'
import { useAppStateSnapshot } from 'state/app-state'
import {
AlertDescription_Shadcn_,
AlertTitle_Shadcn_,
Alert_Shadcn_,
Button,
CommandGroup_Shadcn_,
CommandItem_Shadcn_,
CommandList_Shadcn_,
Command_Shadcn_,
PopoverContent_Shadcn_,
PopoverTrigger_Shadcn_,
Popover_Shadcn_,
} from 'ui'
import { useIsAPIDocsSidePanelEnabled } from '../App/FeaturePreview/FeaturePreviewContext'
import { navigateToSection } from './Content/Content.utils'
import { DOCS_RESOURCE_CONTENT } from './ProjectAPIDocs.constants'
const SecondLevelNav = () => {
const { ref } = useParams()
const snap = useAppStateSnapshot()
const [open, setOpen] = useState(false)
const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled()
const { data } = useOpenAPISpecQuery({ projectRef: ref })
const tables = data?.tables ?? []
const functions = data?.functions ?? []
const [section, resource] = snap.activeDocsSection
const { data: buckets } = useBucketsQuery({ projectRef: ref })
const { data: edgeFunctions } = useEdgeFunctionsQuery({ projectRef: ref })
const bucket = (buckets ?? []).find((b) => b.name === resource)
const content: { [key: string]: { title: string; options: any[]; docsUrl: string } } = {
entities: {
title: 'Tables & Views',
options: tables,
docsUrl: `${DOCS_URL}/reference/javascript/select`,
},
'stored-procedures': {
title: 'Stored Procedures',
options: functions,
docsUrl: `${DOCS_URL}/reference/javascript/rpc`,
},
storage: {
title: 'Storage',
options: buckets ?? [],
docsUrl: `${DOCS_URL}/reference/javascript/storage-createbucket`,
},
'edge-functions': {
title: 'Edge Functions',
options: edgeFunctions ?? [],
docsUrl: `${DOCS_URL}/reference/javascript/functions-invoke`,
},
}
const updateSection = (value: string) => {
snap.setActiveDocsSection([snap.activeDocsSection[0], value])
setOpen(false)
}
const menuItems = Object.values(DOCS_RESOURCE_CONTENT).filter(
(content) => content.category === snap.activeDocsSection[0]
)
return (
<div className="py-4">
<div className="px-4 flex items-center space-x-2 mb-2">
{isNewAPIDocsEnabled && (
<Button
type="text"
icon={<ChevronLeft />}
className="px-1"
onClick={() => snap.setActiveDocsSection([snap.activeDocsSection[0]])}
/>
)}
<p className="text-sm text-foreground-light capitalize">{content[section].title}</p>
</div>
<Popover_Shadcn_ open={open} onOpenChange={setOpen} modal={false}>
<PopoverTrigger_Shadcn_ asChild>
<div className="px-4">
<Button block type="default" size="small" className="[&>span]:w-full">
<div>
<div className="flex items-center justify-between w-full">
<p>{snap.activeDocsSection[1]}</p>
<div>
<Code className="rotate-90" strokeWidth={1.5} size={12} />
</div>
</div>
</div>
</Button>
</div>
</PopoverTrigger_Shadcn_>
<PopoverContent_Shadcn_ className="p-0 w-60" side="bottom" align="center">
<Command_Shadcn_>
<CommandList_Shadcn_>
<CommandGroup_Shadcn_>
{content[section].options.map((option) => (
<CommandItem_Shadcn_
key={option.name}
className="cursor-pointer"
onSelect={() => updateSection(option.name)}
onClick={() => updateSection(option.name)}
>
<p>{option.name}</p>
</CommandItem_Shadcn_>
))}
</CommandGroup_Shadcn_>
</CommandList_Shadcn_>
</Command_Shadcn_>
</PopoverContent_Shadcn_>
</Popover_Shadcn_>
<div className="px-2 py-4 space-y-2">
{menuItems.map((item) => {
if (section === 'storage' && bucket !== undefined) {
if (
(!bucket.public && item.key === 'retrieve-public-url') ||
(bucket.public && item.key === 'create-signed-url')
)
return null
}
return (
<p
key={item.key}
title={item.title}
className="text-sm text-foreground-light px-4 hover:text-foreground transition cursor-pointer"
onClick={() => navigateToSection(item.key)}
>
{item.title}
</p>
)
})}
</div>
<div className="px-4 py-4 border-t space-y-2">
<Alert_Shadcn_ className="p-3">
<AlertTitle_Shadcn_>
<p className="text-xs">Unable to find what you're looking for?</p>
</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_ className="space-y-1">
<p className="text-xs !leading-normal">
The API methods shown here are only the commonly used ones to get you started building
quickly.
</p>
<p className="text-xs !leading-normal">
Head over to our docs site for the full API documentation.
</p>
<DocsButton className="!mt-2" href={content[section].docsUrl} />
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
</div>
</div>
)
}
export default SecondLevelNav