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.
This commit is contained in:
dayuan.jiang
2026-10-11 20:56:07 +09:00
parent 66c9daf5ca
commit 0de1cdfe7c
12 changed files with 885 additions and 46 deletions
+10 -3
View File
@@ -13,12 +13,17 @@ import type { ShellConfig } from "./runtime-config"
* protocol): mounted once inside DiagramProvider. Server writes go on the
* canvas through loadDiagram, as one undo step when they can; the user's
* edits are pushed; the server's export and sync requests are answered.
* Returns the connection state for the status bar.
* Returns the connection state for the status bar, and the sync itself for
* the version cards (History and restores go through it).
*/
export function useMcpSync(config: ShellConfig): SyncStatus {
export function useMcpSync(config: ShellConfig): {
status: SyncStatus
sync: McpSync | null
} {
const dict = useDictionary()
const diagram = useDiagram()
const [status, setStatus] = useState<SyncStatus>("waiting")
const [sync, setSync] = useState<McpSync | null>(null)
const syncRef = useRef<McpSync | null>(null)
// The provider's functions are new on every render; the sync (created
// once) reads the latest through refs
@@ -54,6 +59,7 @@ export function useMcpSync(config: ShellConfig): SyncStatus {
onStatus: setStatus,
})
syncRef.current = sync
setSync(sync)
sync.setReady(diagramRef.current.isDrawioReady)
sync.start()
@@ -86,6 +92,7 @@ export function useMcpSync(config: ShellConfig): SyncStatus {
window.removeEventListener("message", onMessage)
sync.stop()
syncRef.current = null
setSync(null)
}
}, [config])
@@ -107,5 +114,5 @@ export function useMcpSync(config: ShellConfig): SyncStatus {
return () => diagram.setCommitHandler(null)
}, [])
return status
return { status, sync }
}