"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