import { CsvColumnsCard } from "./CsvColumnsCard"; import { MappingCard } from "./MappingCard"; import { DndContext, closestCenter, MeasuringStrategy, DragOverlay, } from "@dnd-kit/core"; import { useState } from "react"; import { Button } from "@/src/components/ui/button"; import { api } from "@/src/utils/api"; import { Progress } from "@/src/components/ui/progress"; import { usePostHogClientCapture } from "@/src/features/posthog-analytics/usePostHogClientCapture"; import { DialogBody, DialogFooter } from "@/src/components/ui/dialog"; import { CsvImportValidationError } from "./CsvImportValidationError"; import { Checkbox } from "@/src/components/ui/checkbox"; import { Label } from "@/src/components/ui/label"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/src/components/ui/tooltip"; import { InfoIcon, GripVertical } from "lucide-react"; import { useCsvMapping } from "@/src/features/datasets/hooks/useCsvMapping"; import { useCsvDragAndDrop } from "@/src/features/datasets/hooks/useCsvDragAndDrop"; import { useCsvImport } from "@/src/features/datasets/hooks/useCsvImport"; import { createPortal } from "react-dom"; import type { CsvPreviewResult } from "@/src/features/datasets/lib/csv/types"; // Helper to extract schema keys from object schema function extractSchemaKeys(schema: unknown): string[] | null { if (!schema || typeof schema !== "object") return null; const schemaObj = schema as Record; if (schemaObj.type !== "object" || !schemaObj.properties) return null; return Object.keys(schemaObj.properties as Record); } export function PreviewCsvImport({ preview, csvFile, projectId, datasetId, setCsvFile, setPreview, setOpen, }: { preview: CsvPreviewResult; csvFile: File | null; projectId: string; datasetId: string; setCsvFile: (file: File | null) => void; setPreview: (preview: CsvPreviewResult | null) => void; setOpen?: (open: boolean) => void; }) { const capture = usePostHogClientCapture(); // Fetch dataset schema const { data: dataset } = api.datasets.byId.useQuery({ projectId, datasetId, }); // Parse schemas const inputSchemaKeys = extractSchemaKeys(dataset?.inputSchema); const expectedOutputSchemaKeys = extractSchemaKeys( dataset?.expectedOutputSchema, ); // Mapping state const mapping = useCsvMapping({ preview, inputSchemaKeys: inputSchemaKeys ?? undefined, expectedOutputSchemaKeys: expectedOutputSchemaKeys ?? undefined, }); // Drag and drop const dragAndDrop = useCsvDragAndDrop({ handlers: { onAddToInputColumn: (columnName) => { const column = preview.columns.find((c) => c.name === columnName); if (column) mapping.addColumnToInput(column); }, onAddToExpectedColumn: (columnName) => { const column = preview.columns.find((c) => c.name === columnName); if (column) mapping.addColumnToExpectedOutput(column); }, onAddToMetadataColumn: (columnName) => { const column = preview.columns.find((c) => c.name === columnName); if (column) mapping.addColumnToMetadata(column); }, onAddToInputSchemaKey: (schemaKey, column) => { mapping.addColumnToInput(column, schemaKey); }, onAddToExpectedSchemaKey: (schemaKey, column) => { mapping.addColumnToExpectedOutput(column, schemaKey); }, onRemoveFromAllMappings: mapping.removeColumnFromAll, }, }); // Import execution const csvImport = useCsvImport({ projectId, datasetId, csvFile, input: mapping.input, expectedOutput: mapping.expectedOutput, metadata: mapping.metadata, }); // Wrapping checkbox (only shown in freeform mode) const [wrapSingleColumn, setWrapSingleColumn] = useState(false); const handleImport = async () => { capture("dataset_item:upload_csv_form_submit"); await csvImport.execute(wrapSingleColumn); // Close dialog on success if (csvImport.progress.status === "complete") { setOpen?.(false); setPreview(null); } }; const handleCancel = () => { setPreview(null); mapping.reset(); setCsvFile(null); csvImport.reset(); }; const isSchemaMode = mapping.input.type === "schema" || mapping.expectedOutput.type === "schema"; return ( <>
{createPortal( {dragAndDrop.activeColumn ? ( dragAndDrop.activeColumn.startsWith("mapped-") ? (
{dragAndDrop.activeColumn.replace("mapped-", "")}
) : (
{dragAndDrop.activeColumn} { preview.columns.find( (col) => col.name === dragAndDrop.activeColumn, )?.inferredType }
) ) : null}
, document.body, )}
{csvImport.validationErrors.length > 0 && ( )}
{!isSchemaMode && (
setWrapSingleColumn(checked === true) } /> When a single csv column is mapped to a dataset item field, wrap its value in an object instead of using the raw value. Example:{" "} {`{"columnName": "value"}`} instead of {`"value"`}
)} {csvImport.progress.status === "processing" && (
)}
); }