import { api } from "@/src/utils/api"; import * as z from "zod/v4"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import { useEffect, useState, useMemo } from "react"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/src/components/ui/form"; import { Button } from "@/src/components/ui/button"; import { useHasProjectAccess } from "@/src/features/rbac/utils/checkProjectAccess"; import { CodeMirrorEditor } from "@/src/components/editor"; import { DatasetSchemaHoverCard } from "./DatasetSchemaHoverCard"; import { useDatasetItemValidation } from "../hooks/useDatasetItemValidation"; import type { DatasetItemDomain, Prisma } from "@langfuse/shared"; import { DatasetItemFieldSchemaErrors } from "./DatasetItemFieldSchemaErrors"; const formSchema = z.object({ input: z.string().refine( (value) => { if (value === "") return true; try { JSON.parse(value); return true; } catch { 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 { 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 { return false; } }, { message: "Invalid input. Please provide a JSON object or double-quoted string.", }, ), }); type Dataset = { id: string; name: string; inputSchema: Prisma.JsonValue | null; expectedOutputSchema: Prisma.JsonValue | null; }; export const EditDatasetItem = ({ projectId, datasetItem, dataset, }: { projectId: string; datasetItem: DatasetItemDomain | null; dataset: Dataset | null; }) => { const [formError, setFormError] = useState(null); const [hasChanges, setHasChanges] = useState(false); const hasAccess = useHasProjectAccess({ projectId: projectId, scope: "datasets:CUD", }); const utils = api.useUtils(); useEffect(() => { if (datasetItem) { form.reset({ input: datasetItem.input ? JSON.stringify(datasetItem.input, null, 2) : "", expectedOutput: datasetItem.expectedOutput ? JSON.stringify(datasetItem.expectedOutput, null, 2) : "", metadata: datasetItem.metadata ? JSON.stringify(datasetItem.metadata, null, 2) : "", }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [datasetItem?.id]); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { input: "", expectedOutput: "", metadata: "", }, }); const inputValue = form.watch("input"); const expectedOutputValue = form.watch("expectedOutput"); // Track if fields have been touched or modified const { touchedFields, dirtyFields } = form.formState; const hasInteractedWithInput = touchedFields.input || dirtyFields.input; const hasInteractedWithExpectedOutput = touchedFields.expectedOutput || dirtyFields.expectedOutput; // Create dataset array for validation hook const datasets = useMemo(() => { if (!dataset) return []; return [dataset]; }, [dataset]); // Validate against dataset schemas const validation = useDatasetItemValidation( inputValue, expectedOutputValue, datasets, ); // Filter validation errors by field const inputErrors = validation.errors.filter((e) => e.field === "input"); const expectedOutputErrors = validation.errors.filter( (e) => e.field === "expectedOutput", ); const updateDatasetItemMutation = api.datasets.updateDatasetItem.useMutation({ onSuccess: () => utils.datasets.invalidate(), onError: (error) => setFormError(error.message), }); function onSubmit(values: z.infer) { if (!!!datasetItem) return; updateDatasetItemMutation.mutate({ projectId: projectId, datasetId: datasetItem.datasetId, datasetItemId: datasetItem.id, input: values.input, expectedOutput: values.expectedOutput, metadata: values.metadata, }); setHasChanges(false); } return (
setHasChanges(true)} >
{formError ? (

Error: {formError}

) : null}
(
Input {dataset?.inputSchema && ( )}
{ setHasChanges(true); field.onChange(v); }} editable={hasAccess} minHeight={200} /> {validation.hasSchemas && inputErrors.length > 0 && hasInteractedWithInput && ( )}
)} /> (
Expected output {dataset?.expectedOutputSchema && ( )}
{ setHasChanges(true); field.onChange(v); }} editable={hasAccess} minHeight={200} /> {validation.hasSchemas && expectedOutputErrors.length > 0 && hasInteractedWithExpectedOutput && ( )}
)} />
( Metadata { setHasChanges(true); field.onChange(v); }} editable={hasAccess} minHeight={100} /> )} />
); };