"use client"; /** * DatabaseView — EMBEDDED database block (exact contract the core editor's * BlockRenderer relies on): * * import { DatabaseView } from "@/components/database/db-embedded"; * * * Renders a database's single named view (or its first view) in a compact, * self-contained frame: a thin toolbar (view name, record count, open-in-full * link) + the view renderer (table/board/gallery/list/calendar/timeline/ * chart/form/dashboard fallback). * * This is the ONLY export name the core depends on — keep it `DatabaseView`. */ import { useMemo } from "react"; import { useRouter, usePathname } from "next/navigation"; import { ExternalLink } from "lucide-react"; import { cn } from "@/lib/utils"; import { DatabaseDto, DatabaseView as ViewDto, RecordDto, UseDatabaseRecordsResult, pageUrlFromPath, useDatabase, useDatabaseRecords } from "@/hooks/use-database"; import { TableView } from "@/components/database/table-view"; import { BoardView } from "@/components/database/board-view"; import { GalleryView } from "@/components/database/gallery-view"; import { ListView } from "@/components/database/list-view"; import { CalendarView } from "@/components/database/calendar-view"; import { TimelineView } from "@/components/database/timeline-view"; import { ChartView } from "@/components/database/chart-view"; import { FormView } from "@/components/form/form-view"; export interface DatabaseViewProps { /** Marks this as an embedded block (vs. the full database page). */ embedded?: boolean; databaseId: string; viewId?: string; className?: string; /** Max rendered rows for the embedded block (kept cheap). */ limit?: number; } function ViewBody({ database, view, records, onOpenRecord, onOpenRecordPage }: { database: DatabaseDto; view: ViewDto; records: UseDatabaseRecordsResult; onOpenRecord: (record: RecordDto) => void; onOpenRecordPage: (record: RecordDto) => void; }) { const properties = database.properties; switch (view.type) { case "table": return ( undefined} onFilterChange={() => undefined} /> ); case "board": return ; case "gallery": return ; case "list": return ; case "calendar": return ; case "timeline": return ; case "chart": return ; case "form": return ( ); case "dashboard": return ; default: return ( undefined} onFilterChange={() => undefined} /> ); } } function EmptyNote({ text }: { text: string }) { return (
{text}
); } export function DatabaseView({ embedded, databaseId, viewId, className, limit = 20 }: DatabaseViewProps) { const router = useRouter(); const pathname = usePathname(); const { data: database, isLoading, error } = useDatabase(databaseId); const view: ViewDto | undefined = useMemo(() => { if (!database) return undefined; if (viewId) return database.views.find((v) => v.id === viewId); return database.views[0]; }, [database, viewId]); const records = useDatabaseRecords(databaseId, { viewId: view?.id ?? viewId ?? null, filter: view?.filter ?? null, sort: view?.sort ?? null, group: view?.group ?? null, pageSize: limit, enabled: !!view }); // Page URLs are /w/[workspace]/page/[pageId] (see app/(app)/w/[workspace]/ // page/[id]/page.tsx). The workspace slug is the SECOND path segment — the // first is the literal "w". (The old code took the first segment, producing // /w/p/{id} → 404 "This page does not exist".) Shared + unit-tested helper: // pageUrlFromPath. const pageUrl = (pageId: string): string => pageUrlFromPath(pathname, pageId); const onOpenRecordPage = (record: RecordDto) => { if (!record.pageId) return; router.push(pageUrl(record.pageId)); }; const onOpenRecord = (record: RecordDto) => onOpenRecordPage(record); if (isLoading) { return (
); } if (error || !database) { return (
This database is no longer available.
); } if (!view) { return (
This database has no views yet.
); } return (
{view.name} · {records.data.totalCount ?? records.data.records.length} records { // New window (the ExternalLink affordance + the user expectation): // the embedded block stays open on the current page. if (database.pageId) window.open(pageUrl(database.pageId), "_blank", "noopener,noreferrer"); }} onKeyDown={(e) => { if (e.key === "Enter" && database.pageId) window.open(pageUrl(database.pageId), "_blank", "noopener,noreferrer"); }} > Open
); }