From f257d8ee99e1cca115ad62ce1f93d0c8cd3dd8db Mon Sep 17 00:00:00 2001 From: "dayuan.jiang" Date: Sun, 11 Oct 2026 17:47:36 +0900 Subject: [PATCH] fix(mcp-server): review fixes for the shell page - a download button in the header opens the web app's export dialog (.drawio, .png, .svg, .drawio.svg), which the classic page had and the shell lacked when it became the default - the shell asks draw.io for the custom library menu (libraries=1), as the classic page did; the web app keeps libraries=0 - the newest card no longer shows "Rendering preview" for good: the sync takes the thumbnail of a diagram the server recovered from its file (saved without pictures) while the canvas kept it, and of a write whose picture was skipped because an edit came first, once the canvas shows the write again - e2e: the get_selection test covers a shape in a container the user entered; a download test saves a .drawio file --- lib/drawio/drawio-config.ts | 5 ++- packages/mcp-server/README.md | 4 +- packages/mcp-server/shell/canvas-shell.tsx | 37 +++++++++++++++-- packages/mcp-server/shell/mcp-sync-core.ts | 27 ++++++++++++- packages/mcp-server/tests/e2e/shell.spec.ts | 44 +++++++++++++++++++++ tests/unit/mcp-shell-config.test.ts | 14 +++++++ tests/unit/mcp-sync-core.test.ts | 41 +++++++++++++++++++ 7 files changed, 164 insertions(+), 8 deletions(-) diff --git a/lib/drawio/drawio-config.ts b/lib/drawio/drawio-config.ts index 13672add..ea6de9d3 100644 --- a/lib/drawio/drawio-config.ts +++ b/lib/drawio/drawio-config.ts @@ -21,6 +21,9 @@ export interface DrawioSource { lang?: string /** No calls to external services (the desktop app) */ offline?: boolean + /** draw.io's custom libraries (File > New Library, Open Library from, + * and the buttons under the shapes); the web app leaves them out */ + libraries?: boolean } /** @@ -53,7 +56,7 @@ export function getDrawioSrc(source: DrawioSource, dark: boolean): string { else params.themes = "1" Object.assign(params, { spin: "0", - libraries: "0", + libraries: source.libraries ? "1" : "0", noSaveBtn: "1", noExitBtn: "1", saveAndExit: "0", diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md index c098f783..b9b9d243 100644 --- a/packages/mcp-server/README.md +++ b/packages/mcp-server/README.md @@ -113,7 +113,7 @@ Use the standard MCP configuration with: - **Edit Support**: Modify existing diagrams with natural language instructions. If any change in an edit fails, nothing is written and the AI gets the reason and the current page XML - **Your Edits Are Kept**: Changes you make in the browser are read before the AI edits again. If the AI overwrites a change you were still making, your version is saved in History - **Version History**: The last 20 versions appear as cards next to the canvas, with a thumbnail and what changed. Restore one, undo and redo the latest, or compare a version with the canvas; or ask the AI to undo (`restore_version`) -- **Export**: Save as `.drawio`, `.png`, `.svg`, or `.drawio.svg` (an SVG with the diagram embedded, which draw.io and `load_diagram` can open again) through `export_diagram`, or export an image from draw.io's **File > Export as** menu in the preview +- **Export**: Save as `.drawio`, `.png`, `.svg`, or `.drawio.svg` (an SVG with the diagram embedded, which draw.io and `load_diagram` can open again) through `export_diagram`, or from the download button in the preview's header - **Multi-page**: List, add, rename, and delete pages, and edit any page - **Auto-save**: Each session's diagram is saved to `~/.next-ai-drawio/.drawio`, and its last 20 versions to `.history.json`, so the diagram, History and undo survive a restart of the MCP client - **Custom Instructions**: keep your own drawing rules in `~/.next-ai-drawio/instructions.md` (for example "Always draw in minimal style"); they are appended to the drawing guide on every call @@ -231,7 +231,7 @@ Like the web app's bundled copy, it has no image proxy (`/drawio/proxy`): images ### Classic preview page -`DRAWIO_PREVIEW_UI=classic` opens the preview page of the previous releases: draw.io with a **History** dialog and a **Download** button, without the outline of the AI's changes, Ctrl+Z for them, the version cards and `get_selection`. It stays for one more release and is then removed. +`DRAWIO_PREVIEW_UI=classic` opens the preview page of the previous releases: draw.io with a **History** dialog and a **Download** button, without the outline of the AI's changes, Ctrl+Z for them, the version cards, Compare and `get_selection`. It stays for one more release and is then removed. ## Troubleshooting diff --git a/packages/mcp-server/shell/canvas-shell.tsx b/packages/mcp-server/shell/canvas-shell.tsx index 6288eae4..1d14fcef 100644 --- a/packages/mcp-server/shell/canvas-shell.tsx +++ b/packages/mcp-server/shell/canvas-shell.tsx @@ -1,10 +1,12 @@ -import { History, Moon, Sun } from "lucide-react" +import { Download, History, Moon, Sun } from "lucide-react" import { useMemo, useState } from "react" import { CanvasStage } from "@/components/canvas/canvas-stage" import { CompareDialog } from "@/components/canvas/compare-dialog" import { VersionStrip } from "@/components/canvas/version-strip" import { VersionsProvider } from "@/components/canvas/versions-context" +import { SaveDialog } from "@/components/save-dialog" import { AppToaster } from "@/components/workspace/app-toaster" +import { useDiagram } from "@/contexts/diagram-context" import { useDictionary } from "@/hooks/use-dictionary" import type { DrawioSource } from "@/lib/drawio/drawio-config" import { cn } from "@/lib/utils" @@ -21,20 +23,24 @@ const iconButton = /** * The MCP preview: the web app's canvas without the chat. A slim bar names * the session and the sync state; the versions strip, the version cards - * (from the server's History) and Compare come from the shared canvas - * components. + * (from the server's History), Compare and the export dialog come from the + * shared canvas components. */ export function CanvasShell({ config }: { config: ShellConfig }) { const dict = useDictionary() const isDark = useSettingsStore((s) => s.isDark) + const { saveDiagramToFile } = useDiagram() const { status, sync } = useMcpSync(config) const versions = useNodeVersions(sync) const [panelOpen, setPanelOpen] = useState(true) + const [saveOpen, setSaveOpen] = useState(false) const drawioSource = useMemo( () => ({ editorUrl: config.drawioBaseUrl, ui: config.drawioUi || undefined, lang: config.drawioLang || undefined, + // As the classic preview page: the user's own shape libraries + libraries: true, }), [config], ) @@ -89,12 +95,22 @@ export function CanvasShell({ config }: { config: ShellConfig }) { )} +