Files
next-ai-draw-io/packages/mcp-server/shell/versions-panel.tsx
T
dayuan.jiang 0de1cdfe7c feat(mcp-server): version cards in the shell from the server's History
The shell's VersionsSource (shell/node-versions-source.ts) reads GET
/api/history through the sync and shows one version per distinct content
(a restore's copy folds into the entry it copies; the blank page is none),
numbered as they first appeared, with what changed since the one before.
The entry the server says is on the canvas marks the version; undo and
redo of the newest version restore the one before it, or it again, through
POST /api/restore, so hand edits stay as versions of their own. The cards
sit in a panel beside the canvas (toggle in the header); the strip and
Compare come from the shared canvas components. The sync tells listeners
once per server version, and when History changed without one, so the
list is read again only then.
2026-10-11 20:56:07 +09:00

51 lines
1.9 KiB
TypeScript

import { useEffect, useRef } from "react"
import { VersionCard } from "@/components/canvas/version-card"
import { useDictionary } from "@/hooks/use-dictionary"
import type { Dictionary } from "@/lib/i18n/dictionaries"
import type { NodeVersion } from "./node-versions-source"
/** What a card says happened: the web app's chat knows the tool that ran,
* the shell tells from who made the entry and what changed */
export function versionLabel(version: NodeVersion, dict: Dictionary): string {
if (version.source === "user" || version.source === "recover") {
return dict.shell.userEdit
}
return version.fromScratch ? dict.versions.created : dict.versions.edited
}
/** The version cards, oldest first, as the web app's chat shows them */
export function VersionsPanel({ versions }: { versions: NodeVersion[] }) {
const dict = useDictionary()
const listRef = useRef<HTMLDivElement>(null)
// Keep the newest version in view
useEffect(() => {
const el = listRef.current
if (el) el.scrollTo({ top: el.scrollHeight, behavior: "smooth" })
}, [versions.length])
return (
<aside
className="flex w-[340px] shrink-0 flex-col border-l border-border bg-surface-0"
data-testid="versions-panel"
>
<div className="flex h-9 shrink-0 items-center px-3.5 text-xs font-medium text-muted-foreground">
{dict.versions.strip}
</div>
<div
ref={listRef}
className="flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto px-3 pb-3 scrollbar-thin"
>
{versions.map((version, i) => (
<VersionCard
key={version.id}
version={version}
isLatest={i === versions.length - 1}
label={versionLabel(version, dict)}
/>
))}
</div>
</aside>
)
}