import { useParams } from 'common' import { Book, BookOpen } from 'lucide-react' import Link from 'next/link' import { Fragment, type ReactNode } from 'react' import SVG from 'react-inlinesvg' import { Button, cn } from 'ui' import { ShimmeringLoader } from 'ui-patterns' import { navigateToSection } from './Content/Content.utils' import { API_DOCS_CATEGORIES, DOCS_CONTENT, DOCS_MENU } from './ProjectAPIDocs.constants' import { useApiDocsFunctions, useApiDocsTables } from './useApiDocsEntities' import { InfiniteListDefault, type RowComponentBaseProps } from '@/components/ui/InfiniteList' import { NotExposedEntitiesIndicator } from '@/components/ui/NotExposedEntitiesIndicator' import { useEdgeFunctionsQuery } from '@/data/edge-functions/edge-functions-query' import { usePaginatedBucketsQuery, type Bucket } from '@/data/storage/buckets-query' import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' import { BASE_PATH, DOCS_URL } from '@/lib/constants' import { useAppStateSnapshot } from '@/state/app-state' type DocsSections = typeof DOCS_MENU type DocsSection = DocsSections[number] type DocsSectionsSubset = readonly DocsSection[] type DocsCategory = DocsSection['key'] type DocsContentRegistry = typeof DOCS_CONTENT type DocsSnippet = DocsContentRegistry[keyof DocsContentRegistry] const Separator = () =>
const MENU_BUTTON_CLASSES = cn( 'w-full px-4', 'text-left text-sm text-foreground-light', 'transition hover:text-foreground' ) /** * Gets the docs menu items based on feature flags. * @returns An array of menu items to be displayed in the docs navigation. */ const useDocsMenu = (): DocsSectionsSubset => { const { projectAuthAll: authEnabled, projectStorageAll: storageEnabled, projectEdgeFunctionAll: edgeFunctionsEnabled, realtimeAll: realtimeEnabled, } = useIsFeatureEnabled([ 'project_auth:all', 'project_storage:all', 'project_edge_function:all', 'realtime:all', ]) return DOCS_MENU.filter((item) => { if (item.key === 'user-management') return authEnabled if (item.key === 'storage') return storageEnabled if (item.key === 'edge-functions') return edgeFunctionsEnabled if (item.key === 'realtime') return realtimeEnabled return true }) } /** * Gets the content snippets for a given documentation category. * @param category - The category of documentation to retrieve snippets for. * @returns An array of content snippets belonging to the specified category. */ const getSectionSnippets = (category: DocsCategory): DocsSnippet[] => Object.values(DOCS_CONTENT).filter((snippet) => snippet.category === category) export const FirstLevelNav = (): ReactNode => { const { ref } = useParams() const snap = useAppStateSnapshot() const currentSection = snap.activeDocsSection[0] const docsMenu = useDocsMenu() return ( <>
) } type SubsectionsProps = { category: DocsCategory } const Subsections = ({ category }: SubsectionsProps): ReactNode => { const snippets = getSectionSnippets(category) return (
{snippets.map((snippet) => ( ))} {category === API_DOCS_CATEGORIES.ENTITIES && } {category === API_DOCS_CATEGORIES.STORED_PROCEDURES && } {category === API_DOCS_CATEGORIES.STORAGE && } {category === API_DOCS_CATEGORIES.EDGE_FUNCTIONS && }
) } const TablesSubsections = (): ReactNode => { const snap = useAppStateSnapshot() const { visibleEntities: tables, excludedCount, isLoading } = useApiDocsTables() // TODO: handle infinite loading of tables return ( <> {isLoading && } {(tables.length > 0 || excludedCount > 0) && } {tables.map((table) => ( ))} snap.setShowProjectApiDocs(false)} /> ) } const DbFunctionsSubsections = (): ReactNode => { const snap = useAppStateSnapshot() const { visibleEntities: functions, excludedCount, isLoading } = useApiDocsFunctions() // TODO: handle virtualization of DB functions return ( <> {isLoading && } {(functions.length > 0 || excludedCount > 0) && } {functions.map((fn) => ( ))} snap.setShowProjectApiDocs(false)} /> ) } const BucketButton = ({ item: bucket, style }: RowComponentBaseProps) => { const snap = useAppStateSnapshot() return ( ) } const StorageSubsections = (): ReactNode => { const { ref } = useParams() const { data, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage } = usePaginatedBucketsQuery({ projectRef: ref, }) const buckets = data?.pages.flatMap((page) => page) ?? [] return ( <> {isLoading && } {buckets.length > 0 && } buckets[idx]?.name} getItemSize={() => 28} hasNextPage={!!hasNextPage} isLoadingNextPage={isFetchingNextPage} onLoadNextPage={fetchNextPage} ItemComponent={BucketButton} LoaderComponent={({ style }) => } /> ) } const EdgeFunctionsSubsections = (): ReactNode => { const { ref } = useParams() const snap = useAppStateSnapshot() const { data: edgeFunctions, isLoading } = useEdgeFunctionsQuery({ projectRef: ref }) // TODO: handle virtualization of edge functions return ( <> {isLoading && } {(edgeFunctions ?? []).length > 0 && } {(edgeFunctions ?? []).map((fn) => ( ))} ) } type LoadingIndicatorProps = { className?: string style?: React.CSSProperties } const LoadingIndicator = ({ className, style }: LoadingIndicatorProps) => ( )