import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { ScrollArea } from "@/components/ui/scrollArea"; import { Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from "@/components/ui/sheet"; import { Message, MessageType } from "@/lib/message"; import { Markdown } from "@/components/ui/markdown"; import { getErrorMessage } from "@/lib/store"; import { useCommitSessionMutation } from "@/lib/store/apis/promptsApi"; import { PromptSession, PromptSessionMessage } from "@/lib/types/prompts"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { cn } from "@/lib/utils"; interface CommitVersionFormData { commitMessage: string; } interface CommitVersionSheetProps { open: boolean; onOpenChange: (open: boolean) => void; session: PromptSession; onCommitted: (versionId: number) => void; } function MessagePreview({ sessionMessage, selected, onToggle, }: { sessionMessage: PromptSessionMessage; selected: boolean; onToggle: () => void; }) { const msg = useMemo(() => Message.deserialize(sessionMessage.message), [sessionMessage.message]); const role = msg.role; const content = msg.content; const hasToolCalls = msg.type === MessageType.CompletionResult && msg.toolCalls && msg.toolCalls.length > 0; return ( ); } export function CommitVersionSheet({ open, onOpenChange, session, onCommitted }: CommitVersionSheetProps) { const [commitSession, { isLoading }] = useCommitSessionMutation(); const [selectedIndices, setSelectedIndices] = useState>(new Set()); const { register, handleSubmit, reset, formState: { errors }, } = useForm({ defaultValues: { commitMessage: "" }, }); // Reset form and select only the first message when sheet opens useEffect(() => { if (open) { reset({ commitMessage: "" }); setSelectedIndices(new Set(session.messages.length > 0 ? [0] : [])); } }, [open, reset, session?.messages?.length]); const toggleMessage = useCallback((index: number) => { setSelectedIndices((prev) => { const next = new Set(prev); if (next.has(index)) { next.delete(index); } else { next.add(index); } return next; }); }, []); const allSelected = selectedIndices.size === session.messages.length; const toggleAll = useCallback(() => { if (allSelected) { setSelectedIndices(new Set()); } else { setSelectedIndices(new Set(session.messages.map((_, i) => i))); } }, [allSelected, session.messages]); async function onSubmit(data: CommitVersionFormData) { if (selectedIndices.size === 0) { toast.error("Please select at least one message to commit"); return; } try { const sortedIndices = Array.from(selectedIndices).sort((a, b) => a - b); const commitData: { commit_message: string; message_indices?: number[] } = { commit_message: data.commitMessage.trim(), }; // Only send message_indices if not all messages are selected if (!allSelected) { commitData.message_indices = sortedIndices; } const result = await commitSession({ id: session.id, promptId: session.prompt_id, data: commitData, }).unwrap(); toast.success("Version committed"); reset(); onCommitted(result.version.id); onOpenChange(false); } catch (err) { toast.error("Failed to commit version", { description: getErrorMessage(err), }); } } return ( { e.preventDefault(); document.getElementById("commitMessage")?.focus(); }} >
Commit as Version Select the messages to include in this version. Uncheck any messages you want to exclude. {/* Messages selection - scrollable */}
{session.messages.map((sessionMsg, index) => ( toggleMessage(index)} /> ))}
{/* Commit message + CTAs - always visible at bottom */}
v.trim().length > 0 || "Commit message cannot be blank", })} autoFocus /> {errors.commitMessage ? (

{errors.commitMessage.message}

) : (

Describe what changed in this version (e.g., "Added error handling instructions")

)}
); }