mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-10-07 02:07:47 +08:00
fix: log Editable SVG saves, use local dates in file names, drop unused Electron dialogs
- /api/log-save accepted only drawio, png and svg, so saving as Editable SVG (xmlsvg) got a 400 and was never recorded in Langfuse - The default download name and the template export name used the UTC date, which is the previous day on mornings in East Asia - Remove the Electron openFile/saveFile IPC handlers, their preload bindings and types; nothing in the app calls them
This commit is contained in:
@@ -4,7 +4,7 @@ import { getLangfuseClient } from "@/lib/langfuse"
|
||||
|
||||
const saveSchema = z.object({
|
||||
filename: z.string().min(1).max(255),
|
||||
format: z.enum(["drawio", "png", "svg"]),
|
||||
format: z.enum(["drawio", "png", "svg", "xmlsvg"]),
|
||||
sessionId: z.string().min(1).max(200).optional(),
|
||||
})
|
||||
|
||||
|
||||
@@ -642,9 +642,8 @@ export const ChatInput = forwardRef<ChatInputRef, ChatInputProps>(
|
||||
dict.save.savedSuccessfully,
|
||||
)
|
||||
}
|
||||
defaultFilename={`diagram-${new Date()
|
||||
.toISOString()
|
||||
.slice(0, 10)}`}
|
||||
// Local date as YYYY-MM-DD (toISOString would give UTC)
|
||||
defaultFilename={`diagram-${new Date().toLocaleDateString("sv-SE")}`}
|
||||
/>
|
||||
{onUrlChange && (
|
||||
<UrlInputDialog
|
||||
|
||||
@@ -224,7 +224,8 @@ export function TemplatePanel({
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement("a")
|
||||
a.href = url
|
||||
a.download = `templates-${new Date().toISOString().split("T")[0]}.json`
|
||||
// Local date as YYYY-MM-DD (toISOString would give UTC)
|
||||
a.download = `templates-${new Date().toLocaleDateString("sv-SE")}.json`
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
|
||||
Vendored
-4
@@ -60,10 +60,6 @@ declare global {
|
||||
maximize: () => void
|
||||
/** Close the window */
|
||||
close: () => void
|
||||
/** Open file dialog and return file path */
|
||||
openFile: () => Promise<string | null>
|
||||
/** Save data to file via save dialog */
|
||||
saveFile: (data: string) => Promise<boolean>
|
||||
/** Get proxy configuration */
|
||||
getProxy: () => Promise<ProxyConfig>
|
||||
/** Set proxy configuration (saves and restarts server) */
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import {
|
||||
app,
|
||||
BrowserWindow,
|
||||
dialog,
|
||||
type IpcMainInvokeEvent,
|
||||
ipcMain,
|
||||
} from "electron"
|
||||
import { app, BrowserWindow, type IpcMainInvokeEvent, ipcMain } from "electron"
|
||||
import { rebuildAppMenu, switchPreset } from "./app-menu"
|
||||
import {
|
||||
type ConfigPreset,
|
||||
@@ -104,60 +98,6 @@ export function registerIpcHandlers(): void {
|
||||
win?.close()
|
||||
})
|
||||
|
||||
// ==================== File Dialogs ====================
|
||||
|
||||
handle("dialog-open-file", async (event) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender)
|
||||
if (!win) return null
|
||||
|
||||
const result = await dialog.showOpenDialog(win, {
|
||||
properties: ["openFile"],
|
||||
filters: [
|
||||
{ name: "Draw.io Files", extensions: ["drawio", "xml"] },
|
||||
{ name: "All Files", extensions: ["*"] },
|
||||
],
|
||||
})
|
||||
|
||||
if (result.canceled || result.filePaths.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Read the file content
|
||||
const fs = await import("node:fs/promises")
|
||||
try {
|
||||
const content = await fs.readFile(result.filePaths[0], "utf-8")
|
||||
return content
|
||||
} catch (error) {
|
||||
console.error("Failed to read file:", error)
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
handle("dialog-save-file", async (event, data: string) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender)
|
||||
if (!win || typeof data !== "string") return false
|
||||
|
||||
const result = await dialog.showSaveDialog(win, {
|
||||
filters: [
|
||||
{ name: "Draw.io Files", extensions: ["drawio"] },
|
||||
{ name: "XML Files", extensions: ["xml"] },
|
||||
],
|
||||
})
|
||||
|
||||
if (result.canceled || !result.filePath) {
|
||||
return false
|
||||
}
|
||||
|
||||
const fs = await import("node:fs/promises")
|
||||
try {
|
||||
await fs.writeFile(result.filePath, data, "utf-8")
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error("Failed to save file:", error)
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
// ==================== Config Presets ====================
|
||||
|
||||
handle("config-presets:get-all", () => {
|
||||
|
||||
@@ -18,10 +18,6 @@ contextBridge.exposeInMainWorld("electronAPI", {
|
||||
maximize: () => ipcRenderer.send("window-maximize"),
|
||||
close: () => ipcRenderer.send("window-close"),
|
||||
|
||||
// File operations
|
||||
openFile: () => ipcRenderer.invoke("dialog-open-file"),
|
||||
saveFile: (data: string) => ipcRenderer.invoke("dialog-save-file", data),
|
||||
|
||||
// Proxy settings
|
||||
getProxy: () => ipcRenderer.invoke("get-proxy"),
|
||||
setProxy: (config: { httpProxy?: string; httpsProxy?: string }) =>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// @vitest-environment node
|
||||
import { describe, expect, it, vi } from "vitest"
|
||||
import { POST as logSave } from "@/app/api/log-save/route"
|
||||
|
||||
// A Langfuse client with a trace to attach the save score to
|
||||
const batch = vi.fn(async () => ({}))
|
||||
vi.mock("@/lib/langfuse", () => ({
|
||||
getLangfuseClient: () => ({
|
||||
api: {
|
||||
trace: { list: async () => ({ data: [{ id: "trace-1" }] }) },
|
||||
ingestion: { batch },
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
function post(body: unknown): Request {
|
||||
return new Request("http://localhost/api/log-save", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
}
|
||||
|
||||
describe("POST /api/log-save", () => {
|
||||
it.each(["drawio", "png", "svg", "xmlsvg"])(
|
||||
"logs a save in %s format",
|
||||
async (format) => {
|
||||
const res = await logSave(
|
||||
post({ filename: "diagram", format, sessionId: "s1" }),
|
||||
)
|
||||
expect(res.status).toBe(200)
|
||||
expect(await res.json()).toEqual({ success: true, logged: true })
|
||||
},
|
||||
)
|
||||
|
||||
it("rejects an unknown format", async () => {
|
||||
const res = await logSave(
|
||||
post({ filename: "diagram", format: "pdf", sessionId: "s1" }),
|
||||
)
|
||||
expect(res.status).toBe(400)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user