add diagnostics report

This commit is contained in:
Marc Diaz
2026-05-08 00:00:30 -04:00
parent 899504f8e2
commit a0c423de67
5 changed files with 83 additions and 0 deletions
+6
View File
@@ -150,6 +150,12 @@ interface Window {
setHasUnsavedChanges: (hasChanges: boolean) => void;
onRequestSaveBeforeClose: (callback: () => Promise<boolean> | boolean) => () => void;
setLocale: (locale: string) => Promise<void>;
saveDiagnostic: (payload: {
error: string;
stack?: string;
projectState: unknown;
logs: string[];
}) => Promise<{ success: boolean; path?: string; canceled?: boolean; error?: string }>;
};
}
+42
View File
@@ -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) };
}
},
);
}
+8
View File
@@ -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);
},
@@ -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<void>;
}
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({
<Bug className="w-3 h-3 text-[#34B27B]" />
{t("links.reportBug")}
</button>
{onSaveDiagnostic && (
<button
type="button"
onClick={onSaveDiagnostic}
className="flex-1 flex items-center justify-center gap-1.5 text-[10px] text-slate-500 hover:text-slate-300 py-1.5 transition-colors"
>
<FileDown className="w-3 h-3 text-slate-400" />
Save Diagnostics
</button>
)}
<button
type="button"
onClick={() => {
@@ -1730,6 +1730,19 @@ export default function VideoEditor() {
}
}, []);
const handleSaveDiagnostic = useCallback(async () => {
const result = await window.electronAPI.saveDiagnostic({
error: exportError ?? "Manual diagnostic export",
projectState: editorState,
logs: [],
});
if (result.success) {
toast.success("Diagnostic file saved");
} else if (!result.canceled) {
toast.error("Failed to save diagnostic file");
}
}, [exportError, editorState]);
if (loading) {
return (
<div className="flex items-center justify-center h-screen bg-background">
@@ -2100,6 +2113,7 @@ export default function VideoEditor() {
onSpeedDelete={handleSpeedDelete}
unsavedExport={unsavedExport}
onSaveUnsavedExport={handleSaveUnsavedExport}
onSaveDiagnostic={handleSaveDiagnostic}
/>
</div>
</div>