fix(mcp-server): review fixes for the shell's sync core

A recovery loads the server's diagram in full and waits for draw.io's
load report, as the classic page does: whether the canvas takes a write
in place is decided inside DiagramProvider, and an autosave of the
canvas being replaced went to the server as an edit when the decision
was wrong. A paper size change alone is pushed again: autosaves are
compared as documents only for draw.io's own copy of a committed write.
A projection stays on screen until draw.io reports the restore load
(5 s at most), the whole export ends in 15 s even when its result POST
hangs, and an export in flight is dropped when draw.io starts over. A
refused poll shows the tab offline. With several pages and the page on
screen unknown, a write loads in full. hasLoadOnlySettings and the
highlight of an AI change are shared with the editor bridge.
This commit is contained in:
dayuan.jiang
2026-10-11 20:56:07 +09:00
parent 5ed8940b48
commit b6bd032c2c
5 changed files with 353 additions and 73 deletions
+28 -13
View File
@@ -262,19 +262,19 @@ function hasShapes(xml: string): boolean {
})
}
// Page settings draw.io applies on a full load only: replacing the page in
// place (Editor.readGraphState) keeps the old ones. (Its adaptive colors and
// theme stay too: a diagram the AI writes does not set them.)
function hasLoadOnlySettings(model: string): boolean {
const page = new DOMParser().parseFromString(
model,
"text/xml",
).documentElement
/**
* Page settings draw.io applies on a full load only: replacing the page in
* place (Editor.readGraphState) keeps the old ones. (Its adaptive colors and
* theme stay too: a diagram the AI writes does not set them.) Takes the
* page's mxGraphModel element; the MCP shell's sync asks the same question
* of a document before it reaches the editor.
*/
export function hasLoadOnlySettings(model: Element): boolean {
return (
page.hasAttribute("backgroundImage") ||
page.hasAttribute("extFonts") ||
page.getAttribute("math") === "1" ||
page.getAttribute("shadow") === "1"
model.hasAttribute("backgroundImage") ||
model.hasAttribute("extFonts") ||
model.getAttribute("math") === "1" ||
model.getAttribute("shadow") === "1"
)
}
@@ -322,7 +322,9 @@ export function canReplaceDiagram(xml: string): boolean {
// A document with them, or replacing one with them, loads in full
return (
model !== null &&
!hasLoadOnlySettings(model) &&
!hasLoadOnlySettings(
new DOMParser().parseFromString(model, "text/xml").documentElement,
) &&
!canvasHasLoadOnlySettings()
)
}
@@ -547,6 +549,19 @@ export function highlightCells(ids: string[], color: string) {
}
}
/**
* Marks the cells an AI change touched in the page's marker color, once
* draw.io has drawn them (the web app's versions and the MCP shell share it)
*/
export function highlightChangedCells(ids: string[]) {
setTimeout(() => {
const marker = getComputedStyle(document.documentElement)
.getPropertyValue("--marker")
.trim()
highlightCells(ids, marker || "#ffd84d")
}, 60)
}
// ---------------------------------------------------------------------------
// Selection
// ---------------------------------------------------------------------------