"use client"; import { useState } from "react"; import Image from "next/image"; import { Clock01Icon, Delete02Icon, Edit02Icon, PlusSignIcon, } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { ScrollArea } from "@/components/ui/scroll-area"; import { useEditor } from "@/editor/use-editor"; import { useVersionsStore } from "@/versions/versions-store"; import { VersionNameDialog } from "@/versions/components/version-name-dialog"; import type { ProjectVersion } from "@/versions/types"; function formatVersionDate({ date }: { date: Date }): string { return new Date(date).toLocaleString(undefined, { dateStyle: "medium", timeStyle: "short", }); } function getVersionTitle({ version }: { version: ProjectVersion }): string { return version.kind === "named" && version.name ? version.name : "Auto-checkpoint"; } export function VersionsButton() { const editor = useEditor(); const isPanelOpen = useVersionsStore((s) => s.isPanelOpen); const setPanelOpen = useVersionsStore((s) => s.setPanelOpen); const isCheckpointDialogOpen = useVersionsStore( (s) => s.isCheckpointDialogOpen, ); const closeCheckpointDialog = useVersionsStore( (s) => s.closeCheckpointDialog, ); const openCheckpointDialog = useVersionsStore((s) => s.openCheckpointDialog); const projectId = useEditor((e) => e.project.getActiveOrNull()?.metadata.id); const versions = useEditor((e) => projectId ? e.versions.getVersions({ projectId }) : [], ); const [restoreTarget, setRestoreTarget] = useState( null, ); const [renameTarget, setRenameTarget] = useState(null); const [deleteTarget, setDeleteTarget] = useState(null); const handlePanelOpenChange = (open: boolean) => { setPanelOpen({ open }); if (open && projectId) { editor.versions.listVersions({ projectId }).catch((error) => { console.error("Failed to refresh versions:", error); }); } }; const handleCreateCheckpoint = (name: string) => { closeCheckpointDialog(); editor.versions.createNamedCheckpoint({ name }).catch((error) => { console.error("Failed to create checkpoint:", error); }); }; return ( <>
Versions
{versions.length === 0 ? (

No versions yet. Create a checkpoint to save a known-good state.

) : (
{versions.map((version) => ( setRestoreTarget(version)} onRename={ version.kind === "named" ? () => setRenameTarget(version) : undefined } onDelete={ version.kind === "named" ? () => setDeleteTarget(version) : undefined } /> ))}
)}
{ if (!open) closeCheckpointDialog(); }} onConfirm={handleCreateCheckpoint} mode="create" /> { if (!open) setRenameTarget(null); }} onConfirm={(name) => { const target = renameTarget; setRenameTarget(null); if (target) { editor.versions .renameVersion({ versionId: target.id, name }) .catch((error) => { console.error("Failed to rename checkpoint:", error); }); } }} mode="rename" initialName={renameTarget?.name ?? ""} /> { if (!open) setRestoreTarget(null); }} > Restore {restoreTarget ? getVersionTitle({ version: restoreTarget }) : ""}? The editor will jump to this version. Your current state is saved as an auto-checkpoint first, so nothing is lost. Cancel { const target = restoreTarget; setRestoreTarget(null); if (target) { editor.versions .restoreVersion({ versionId: target.id }) .catch((error) => { console.error("Failed to restore version:", error); }); } }} > Restore { if (!open) setDeleteTarget(null); }} > Delete {deleteTarget ? getVersionTitle({ version: deleteTarget }) : ""}? This checkpoint is removed permanently. The current state of the project is not affected. Cancel { const target = deleteTarget; setDeleteTarget(null); if (target) { editor.versions .deleteVersion({ versionId: target.id }) .catch((error) => { console.error("Failed to delete checkpoint:", error); }); } }} > Delete ); } function VersionRow({ version, onRestore, onRename, onDelete, }: { version: ProjectVersion; onRestore: () => void; onRename?: () => void; onDelete?: () => void; }) { return (
{onRename && ( )} {onDelete && ( )}
); }