fix: keep Mermaid diagram edges reachable and add PNG export

Fix oversized diagram alignment in the large-diagram viewer and provide complete PNG downloads independent of zoom and pan. Cover the full window and shared native drag handling, with regression checks for both themes and narrow windows.

Validation: 58 focused tests passed, including 9 Electron scenarios and 10 PNG downloads; typecheck and lint passed. Full-suite runs did not complete.

Release note: Mermaid 大图放大后可浏览全部边缘,并可从弹窗导出完整 PNG 图片。
This commit is contained in:
mesalogo
2026-09-23 11:53:09 +08:00
parent be84534e77
commit 785b1ee468
14 changed files with 427 additions and 13 deletions
+59
View File
@@ -0,0 +1,59 @@
// @vitest-environment node
import { spawn } from 'node:child_process'
import { copyFile, mkdtemp, rm } from 'node:fs/promises'
import { createRequire } from 'node:module'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import react from '@vitejs/plugin-react'
import { createServer } from 'vite'
import { expect, it } from 'vitest'
it('keeps real Mermaid modal edges reachable and downloads complete PNGs', async () => {
const directory = await mkdtemp(join(tmpdir(), 'goodbuddy-mermaid-'))
const server = await createServer({
configFile: false,
root: resolve('.'),
cacheDir: join(directory, 'vite'),
plugins: [react(), {
name: 'mermaid-regression',
configureServer(server) {
server.middlewares.use('/mermaid.html', async (_request, response) => {
response.setHeader('Content-Type', 'text/html; charset=utf-8')
response.end(await server.transformIndexHtml('/mermaid.html',
'<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"></head><body><div id="root"></div><script type="module" src="/tests/support/mermaid-viewer-regression.tsx"></script></body></html>'))
})
}
}],
server: { host: '127.0.0.1', port: 0, watch: null }
})
try {
await server.listen()
const env: NodeJS.ProcessEnv = { ...process.env,
GOODBUDDY_MERMAID_URL: server.resolvedUrls!.local[0] + 'mermaid.html',
GOODBUDDY_MERMAID_DIRECTORY: directory }
delete env.ELECTRON_RUN_AS_NODE
const driver = join(directory, 'driver.mjs')
await copyFile(resolve('tests/support/mermaid-viewer-driver.mjs'), driver)
const child = spawn(createRequire(import.meta.url)('electron'), [driver], {
env, stdio: ['ignore', 'pipe', 'pipe']
})
let output = ''
child.stdout.on('data', data => { output += data })
child.stderr.on('data', data => { output += data })
const timeout = setTimeout(() => child.kill(), 240_000)
try {
const code = await new Promise((resolve, reject) => {
child.once('exit', resolve)
child.once('error', reject)
})
expect(code, output).toBe(0)
process.stdout.write(output.split(/\r?\n/u).filter(line => line.startsWith('Mermaid')).join('\n') + '\n')
} finally {
clearTimeout(timeout)
if (child.exitCode === null) child.kill()
}
} finally {
await server.close()
await rm(directory, { recursive: true, force: true })
}
}, 270_000)