/* Copyright 2026 Marimo. All rights reserved. */ import { useAtomValue } from "jotai"; import { PlusSquareIcon } from "lucide-react"; import React, { Suspense } from "react"; import { useLocale } from "react-aria"; import { maybeAddAltairImport } from "@/core/cells/add-missing-import"; import { useCellActions } from "@/core/cells/cells"; import { useLastFocusedCellId } from "@/core/cells/focus"; import { autoInstantiateAtom } from "@/core/config/config"; import type { SQLTableContext } from "@/core/datasets/data-source-connections"; import type { DataColumnPreview, DataTable, DataTableColumn, DataType, } from "@/core/kernel/messages"; import { useRequestClient } from "@/core/network/requests"; import { useOnMount } from "@/hooks/useLifecycle"; import type { TopLevelFacetedUnitSpec } from "@/plugins/impl/data-explorer/queries/types"; import { type Theme, useTheme } from "@/theme/useTheme"; import { Events } from "@/utils/events"; import { prettyNumber } from "@/utils/numbers"; import { LazyVegaEmbed } from "../charts/lazy"; import type { ColumnHeaderStatsKey } from "../data-table/types"; import { CopyClipboardIcon } from "../icons/copy-icon"; import { Spinner } from "../icons/spinner"; import { Button } from "../ui/button"; import { Tooltip } from "../ui/tooltip"; import { ColumnPreviewContainer } from "./components"; import { InstallPackageButton } from "./install-package-button"; import { convertStatsName, sqlCode } from "./utils"; export const DatasetColumnPreview: React.FC<{ table: DataTable; column: DataTableColumn; onAddColumnChart: (code: string) => void; preview: DataColumnPreview | undefined; sqlTableContext?: SQLTableContext; }> = ({ table, column, preview, onAddColumnChart, sqlTableContext }) => { const { theme } = useTheme(); const { previewDatasetColumn } = useRequestClient(); const { locale } = useLocale(); const previewColumn = () => { previewDatasetColumn({ source: table.source, tableName: table.name, columnName: column.name, sourceType: table.source_type, fullyQualifiedTableName: sqlTableContext ? `${sqlTableContext.database}.${sqlTableContext.schema}.${table.name}` : table.name, }); }; useOnMount(() => { if (preview) { return; } // Do not fetch previews for custom SQL connections or catalogs if (table.source_type === "connection" || table.source_type === "catalog") { return; } previewColumn(); }); if (table.source_type === "connection") { return ( {column.name} ({column.external_type}) ); } if (table.source_type === "catalog") { return ( {column.name} ({column.external_type}) ); } if (!preview) { return Loading...; } const error = preview.error && renderPreviewError({ error: preview.error, missingPackages: preview.missing_packages, refetchPreview: previewColumn, }); const stats = preview.stats && renderStats({ stats: preview.stats, dataType: column.type, locale }); const chart = preview.chart_spec && renderChart(preview.chart_spec, theme); const addDataframeChart = preview.chart_code && table.source_type === "local" && ( ); const addSQLChart = table.source_type === "duckdb" && ( ); if (!error && !stats && !chart) { return No data; } return ( {error} {addDataframeChart} {addSQLChart} {chart} {stats} ); }; export function renderPreviewError({ error, missingPackages, refetchPreview, }: { error: string; missingPackages?: string[] | null; refetchPreview?: () => void; }) { return (
{error} {missingPackages && ( )}
); } interface RenderStatsProps { stats: Partial>; dataType: DataType; locale: string; } export function renderStats({ stats, dataType, locale }: RenderStatsProps) { return (
{Object.entries(stats).map(([key, value]) => { if (value == null) { return null; } return (
{convertStatsName(key as ColumnHeaderStatsKey, dataType)} {prettyNumber(value, locale)}
); })}
); } const LoadingChart = (
); export function renderChart(chartSpec: string, theme: Theme) { const updateSpec = (spec: TopLevelFacetedUnitSpec) => { return { ...spec, background: "transparent", config: { ...spec.config, background: "transparent" }, }; }; return ( ); } export const AddDataframeChart: React.FC<{ chartCode: string; }> = ({ chartCode }) => { const autoInstantiate = useAtomValue(autoInstantiateAtom); const lastFocusedCellId = useLastFocusedCellId(); const { createNewCell } = useCellActions(); const handleAddColumn = (chartCode: string) => { if (chartCode.includes("alt")) { maybeAddAltairImport({ autoInstantiate, createNewCell, fromCellId: lastFocusedCellId, }); } createNewCell({ code: chartCode, before: false, cellId: lastFocusedCellId ?? "__end__", }); }; return ( ); };