mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-10-11 20:19:51 +08:00
fix(mcp-server): review fixes for the preview URL and the theme menu
The stalled-tab note names the page start_session opened (the shell with DRAWIO_PREVIEW_UI=shell) instead of the classic page. With the shell not built, start_session opens the classic page and the server says so at startup, as it does for a missing dist/drawio. BROWSER=none skips the system browser, as Vite and CRA dev servers do: the e2e tests set it. Without a fixed DRAWIO_UI, the shell's draw.io URL carries themes=1 so Extras > Theme is offered, as on the classic page.
This commit is contained in:
@@ -47,7 +47,10 @@ export function getDrawioSrc(source: DrawioSource, dark: boolean): string {
|
||||
proto: "json",
|
||||
configure: "1",
|
||||
}
|
||||
// Without a fixed theme, embedded draw.io shows Extras > Theme only
|
||||
// with themes=1 (its isThemeMenuVisible)
|
||||
if (source.ui) params.ui = source.ui
|
||||
else params.themes = "1"
|
||||
Object.assign(params, {
|
||||
spin: "0",
|
||||
libraries: "0",
|
||||
|
||||
@@ -190,6 +190,7 @@ To give the AI your own drawing rules, write them in `~/.next-ai-drawio/instruct
|
||||
| `DRAWIO_DARK` | `auto` | Dark mode of the draw.io editor: `auto` follows the system, `1` forces dark, `0` forces light. The page header keeps following the system. |
|
||||
| `DRAWIO_PREVIEW_UI` | `classic` | The preview page `start_session` opens. `shell` opens the new canvas page built from the web app's canvas: it syncs with the server like the classic page, and an AI change of the page on screen is marked and undone with one Ctrl+Z (in progress: no History panel or download yet). |
|
||||
| `DRAWIO_AUTO_SCREENSHOT` | unset | Set to `true` to attach a screenshot to every `create_new_diagram` and `edit_diagram` result, so the AI checks each drawing. Costs 2 to 10 s per call; the preview tab must be open and in front. A call can still pass `screenshot: false`. |
|
||||
| `BROWSER` | unset | Set to `none` and `start_session` does not open the preview in the system browser (the convention of Vite and Create React App dev servers); the result still names the URL. |
|
||||
| `DEBUG` | unset | Set to `true` to log debug messages to stderr. |
|
||||
|
||||
### Private Deployment (Self-hosted draw.io)
|
||||
|
||||
@@ -122,7 +122,9 @@ export function previewUrl(
|
||||
sessionId: string,
|
||||
ui: PreviewUi = PREVIEW_UI,
|
||||
): string {
|
||||
const path = ui === "shell" ? "/shell/" : ""
|
||||
// The classic page stands in while the shell is not built (a run from
|
||||
// the sources), as embed.diagrams.net does for a missing dist/drawio
|
||||
const path = ui === "shell" && shellDir !== null ? "/shell/" : ""
|
||||
return `http://localhost:${port}${path}?mcp=${sessionId}`
|
||||
}
|
||||
|
||||
@@ -430,6 +432,11 @@ export function startHttpServer(port = 6002): Promise<number> {
|
||||
"No bundled draw.io (dist/drawio missing); the preview loads it from embed.diagrams.net",
|
||||
)
|
||||
}
|
||||
if (PREVIEW_UI === "shell" && shellDir === null) {
|
||||
log.warn(
|
||||
"The canvas shell is not built (dist/shell missing); start_session opens the classic page",
|
||||
)
|
||||
}
|
||||
resolve(port)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -382,9 +382,10 @@ registerWriteTool(
|
||||
lastSeenXml: "",
|
||||
}
|
||||
|
||||
// Open browser
|
||||
// Open the browser. BROWSER=none (the convention of CRA and Vite
|
||||
// dev servers) skips it: the e2e tests and headless hosts set it
|
||||
const browserUrl = previewUrl(port, sessionId)
|
||||
await open(browserUrl)
|
||||
if (process.env.BROWSER !== "none") await open(browserUrl)
|
||||
|
||||
// A saved diagram comes back from its file. lastSeenXml stays
|
||||
// empty, so edit_diagram asks for get_diagram first.
|
||||
@@ -1287,7 +1288,7 @@ function previewStalled(sessionId: string): boolean {
|
||||
* already succeeded must not run again, so it points to screenshot_diagram.
|
||||
*/
|
||||
function previewStalledNote(sessionId: string, next = "then retry") {
|
||||
return `The preview tab is not responding (browsers pause background tabs). Ask the user to bring the preview tab to the front (http://localhost:${getServerPort()}?mcp=${sessionId}), ${next}.`
|
||||
return `The preview tab is not responding (browsers pause background tabs). Ask the user to bring the preview tab to the front (${previewUrl(getServerPort(), sessionId)}), ${next}.`
|
||||
}
|
||||
|
||||
function previewStalledError(sessionId: string) {
|
||||
|
||||
@@ -870,6 +870,15 @@ describe("canvas shell page", () => {
|
||||
expect(previewUrl(6002, "mcp-x", "classic")).toBe(
|
||||
"http://localhost:6002?mcp=mcp-x",
|
||||
)
|
||||
// Not built: the classic page, which works, rather than a 404
|
||||
setShellDir(null)
|
||||
try {
|
||||
expect(previewUrl(6002, "mcp-x", "shell")).toBe(
|
||||
"http://localhost:6002?mcp=mcp-x",
|
||||
)
|
||||
} finally {
|
||||
setShellDir(shellDir)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { readFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import { describe, expect, it } from "vitest"
|
||||
import { getDrawioSrc } from "@/lib/drawio/drawio-config"
|
||||
import { i18n } from "@/lib/i18n/config"
|
||||
import {
|
||||
getShellDictionary,
|
||||
@@ -59,6 +60,25 @@ describe("shell runtime config", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("shell draw.io URL", () => {
|
||||
it("offers draw.io's theme menu unless a theme is fixed", () => {
|
||||
// Embedded draw.io shows Extras > Theme only with themes=1 and no ui
|
||||
const free = new URL(
|
||||
getDrawioSrc({ editorUrl: "/drawio/index.html" }, false),
|
||||
)
|
||||
expect(free.searchParams.get("themes")).toBe("1")
|
||||
expect(free.searchParams.get("ui")).toBeNull()
|
||||
const fixed = new URL(
|
||||
getDrawioSrc(
|
||||
{ editorUrl: "/drawio/index.html", ui: "kennedy" },
|
||||
false,
|
||||
),
|
||||
)
|
||||
expect(fixed.searchParams.get("ui")).toBe("kennedy")
|
||||
expect(fixed.searchParams.get("themes")).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe("shell language", () => {
|
||||
it("maps language tags to the dictionaries we have", () => {
|
||||
expect(matchLocale("en-US")).toBe("en")
|
||||
|
||||
Reference in New Issue
Block a user