From a0c423de677f46a2d04fbf64b7fc5c226b355c29 Mon Sep 17 00:00:00 2001 From: Marc Diaz Date: Fri, 8 May 2026 00:00:30 -0400 Subject: [PATCH] add diagnostics report --- electron/electron-env.d.ts | 6 +++ electron/ipc/handlers.ts | 42 +++++++++++++++++++ electron/preload.ts | 8 ++++ src/components/video-editor/SettingsPanel.tsx | 13 ++++++ src/components/video-editor/VideoEditor.tsx | 14 +++++++ 5 files changed, 83 insertions(+) diff --git a/electron/electron-env.d.ts b/electron/electron-env.d.ts index d9ebab272..6d3d9d517 100644 --- a/electron/electron-env.d.ts +++ b/electron/electron-env.d.ts @@ -150,6 +150,12 @@ interface Window { setHasUnsavedChanges: (hasChanges: boolean) => void; onRequestSaveBeforeClose: (callback: () => Promise | boolean) => () => void; setLocale: (locale: string) => Promise; + saveDiagnostic: (payload: { + error: string; + stack?: string; + projectState: unknown; + logs: string[]; + }) => Promise<{ success: boolean; path?: string; canceled?: boolean; error?: string }>; }; } diff --git a/electron/ipc/handlers.ts b/electron/ipc/handlers.ts index 7361b26fc..20154bc42 100644 --- a/electron/ipc/handlers.ts +++ b/electron/ipc/handlers.ts @@ -1,5 +1,6 @@ import fs from "node:fs/promises"; import { createRequire } from "node:module"; +import os from "node:os"; import path from "node:path"; import { fileURLToPath } from "node:url"; @@ -1317,4 +1318,45 @@ export function registerIpcHandlers( return { success: false, error: String(error) }; } }); + + ipcMain.handle( + "save-diagnostic", + async ( + _, + payload: { error: string; stack?: string; projectState: unknown; logs: string[] }, + ) => { + const { filePath, canceled } = await dialog.showSaveDialog({ + title: "Save Diagnostic File", + defaultPath: `openscreen-diagnostic-${Date.now()}.json`, + filters: [{ name: "JSON", extensions: ["json"] }], + }); + + if (canceled || !filePath) return { success: false, canceled: true }; + + const diagnostic = { + timestamp: new Date().toISOString(), + appVersion: app.getVersion(), + platform: process.platform, + arch: process.arch, + osRelease: os.release(), + osVersion: os.version(), + totalMemoryMB: Math.round(os.totalmem() / 1024 / 1024), + nodeVersion: process.versions.node, + electronVersion: process.versions.electron, + chromeVersion: process.versions.chrome, + error: payload.error, + stack: payload.stack, + projectState: payload.projectState, + recentLogs: payload.logs, + }; + + try { + await fs.writeFile(filePath, JSON.stringify(diagnostic, null, 2), "utf-8"); + return { success: true, path: filePath }; + } catch (error) { + console.error("Failed to write diagnostic file:", error); + return { success: false, error: String(error) }; + } + }, + ); } diff --git a/electron/preload.ts b/electron/preload.ts index 6c705d7b8..9149756c5 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -134,6 +134,14 @@ contextBridge.exposeInMainWorld("electronAPI", { setLocale: (locale: string) => { return ipcRenderer.invoke("set-locale", locale); }, + saveDiagnostic: (payload: { + error: string; + stack?: string; + projectState: unknown; + logs: string[]; + }) => { + return ipcRenderer.invoke("save-diagnostic", payload); + }, setMicrophoneExpanded: (expanded: boolean) => { ipcRenderer.send("hud:setMicrophoneExpanded", expanded); }, diff --git a/src/components/video-editor/SettingsPanel.tsx b/src/components/video-editor/SettingsPanel.tsx index 76ff762dd..377cbbee7 100644 --- a/src/components/video-editor/SettingsPanel.tsx +++ b/src/components/video-editor/SettingsPanel.tsx @@ -3,6 +3,7 @@ import { ChevronDown, Crop, Download, + FileDown, Film, Image, Lock, @@ -240,6 +241,7 @@ interface SettingsPanelProps { webcamSizePreset?: WebcamSizePreset; onWebcamSizePresetChange?: (size: WebcamSizePreset) => void; onWebcamSizePresetCommit?: () => void; + onSaveDiagnostic?: () => Promise; } export default SettingsPanel; @@ -327,6 +329,7 @@ export function SettingsPanel({ webcamSizePreset = DEFAULT_WEBCAM_SIZE_PRESET, onWebcamSizePresetChange, onWebcamSizePresetCommit, + onSaveDiagnostic, }: SettingsPanelProps) { const t = useScopedT("settings"); // Resolved URLs are for DOM rendering only (backgroundImage). The canonical @@ -1682,6 +1685,16 @@ export function SettingsPanel({ {t("links.reportBug")} + {onSaveDiagnostic && ( + + )}