import { Button } from "@/src/components/ui/button"; import * as z from "zod/v4"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/src/components/ui/form"; import { api } from "@/src/utils/api"; import { useState } from "react"; import { CodeMirrorEditor } from "@/src/components/editor"; import { type Prisma } from "@langfuse/shared"; import { cn } from "@/src/utils/tailwind"; import { usePostHogClientCapture } from "@/src/features/posthog-analytics/usePostHogClientCapture"; import { InputCommand, InputCommandEmpty, InputCommandGroup, InputCommandInput, InputCommandItem, } from "@/src/components/ui/input-command"; import { Popover, PopoverContent, PopoverTrigger, } from "@/src/components/ui/popover"; import { Check, ChevronsUpDown } from "lucide-react"; import { Badge } from "@/src/components/ui/badge"; import { ScrollArea } from "@/src/components/ui/scroll-area"; import { DialogBody, DialogFooter } from "@/src/components/ui/dialog"; const formSchema = z.object({ datasetIds: z.array(z.string()).min(1, "Select at least one dataset"), input: z.string().refine( (value) => { if (value === "") return true; try { JSON.parse(value); return true; } catch (error) { return false; } }, { message: "Invalid input. Please provide a JSON object or double-quoted string.", }, ), expectedOutput: z.string().refine( (value) => { if (value === "") return true; try { JSON.parse(value); return true; } catch (error) { return false; } }, { message: "Invalid input. Please provide a JSON object or double-quoted string.", }, ), metadata: z.string().refine( (value) => { if (value === "") return true; try { JSON.parse(value); return true; } catch (error) { return false; } }, { message: "Invalid input. Please provide a JSON object or double-quoted string.", }, ), }); const formatJsonValue = (value: Prisma.JsonValue | undefined): string => { if (value === undefined) return ""; if (typeof value === "string") { try { // Parse the string and re-stringify with proper formatting const parsed = JSON.parse(value); return JSON.stringify(parsed, null, 2); } catch { // If it's not valid JSON, stringify the string itself return JSON.stringify(value, null, 2); } } return JSON.stringify(value, null, 2); }; export const NewDatasetItemForm = (props: { projectId: string; traceId?: string; observationId?: string; input?: Prisma.JsonValue; output?: Prisma.JsonValue; metadata?: Prisma.JsonValue; datasetId?: string; className?: string; onFormSuccess?: () => void; currentDatasetId?: string; }) => { const [formError, setFormError] = useState(null); const capture = usePostHogClientCapture(); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { datasetIds: props.datasetId ? [props.datasetId] : [], input: formatJsonValue(props.input), expectedOutput: formatJsonValue(props.output), metadata: formatJsonValue(props.metadata), }, }); const selectedDatasetCount = form.watch("datasetIds").length; const datasets = api.datasets.allDatasetMeta.useQuery({ projectId: props.projectId, }); const utils = api.useUtils(); const createManyDatasetItemsMutation = api.datasets.createManyDatasetItems.useMutation({ onSuccess: () => utils.datasets.invalidate(), onError: (error) => setFormError(error.message), }); function onSubmit(values: z.infer) { if (props.traceId) { capture("dataset_item:new_from_trace_form_submit", { object: props.observationId ? "observation" : "trace", }); } else { capture("dataset_item:new_form_submit"); } createManyDatasetItemsMutation .mutateAsync({ projectId: props.projectId, items: values.datasetIds.map((datasetId) => ({ datasetId, input: values.input, expectedOutput: values.expectedOutput, metadata: values.metadata, sourceTraceId: props.traceId, sourceObservationId: props.observationId, })), }) .then(() => { props.onFormSuccess?.(); form.reset(); }) .catch((error) => { console.error(error); }); } return (
( Target datasets No datasets found. {datasets.data?.map((dataset) => ( { const newValue = field.value.includes( dataset.id, ) ? field.value.filter( (id) => id !== dataset.id, ) : [...field.value, dataset.id]; field.onChange(newValue); }} > {dataset.name} {dataset.id === props.currentDatasetId && ( (current) )} ))} {field.value.length > 0 && (
{field.value.map((datasetId) => { const dataset = datasets.data?.find( (d) => d.id === datasetId, ); return ( {dataset?.name || datasetId} ); })}
)}
)} />
( Input )} /> ( Expected output )} />
( Metadata )} />
{formError ? (

Error: {formError}

) : null}
); };