Skip to content

add diagnostics report#552

Merged
siddharthvaddem merged 1 commit intosiddharthvaddem:mainfrom
marcgabe15:feature/diagnostics
May 8, 2026
Merged

add diagnostics report#552
siddharthvaddem merged 1 commit intosiddharthvaddem:mainfrom
marcgabe15:feature/diagnostics

Conversation

@marcgabe15
Copy link
Copy Markdown
Collaborator

@marcgabe15 marcgabe15 commented May 8, 2026

Pull Request Template

Description

This adds in a a way to send in a diagnostics report (Will add a way to buffer and logger in later pr)

Motivation

IMG_8533 ## Type of Change - [ ] New Feature - [ ] Bug Fix - [ ] Refactor / Code Cleanup - [ ] Documentation Update - [ ] Other (please specify)

Related Issue(s)

Screenshots / Video

Screenshot (if applicable):

{
  "timestamp": "2026-05-08T03:54:05.078Z",
  "appVersion": "1.4.0",
  "platform": "darwin",
  "arch": "arm64",
  "osRelease": "25.4.0",
  "osVersion": "Darwin Kernel Version 25.4.0: Thu Mar 19 19:31:17 PDT 2026; root:xnu-12377.101.15~1/RELEASE_ARM64_T6020",
  "totalMemoryMB": 16384,
  "nodeVersion": "24.14.1",
  "electronVersion": "41.2.1",
  "chromeVersion": "146.0.7680.188",
  "error": "Manual diagnostic export",
  "projectState": {
    "zoomRegions": [],
    "trimRegions": [],
    "speedRegions": [],
    "annotationRegions": [],
    "cropRegion": {
      "x": 0,
      "y": 0,
      "width": 1,
      "height": 1
    },
    "wallpaper": "/wallpapers/wallpaper1.jpg",
    "shadowIntensity": 0,
    "showBlur": false,
    "motionBlurAmount": 0,
    "borderRadius": 0,
    "padding": 50,
    "aspectRatio": "16:9",
    "webcamLayoutPreset": "picture-in-picture",
    "webcamMaskShape": "rectangle",
    "webcamSizePreset": 25,
    "webcamPosition": null,
    "cursorHighlight": {
      "enabled": false,
      "style": "ring",
      "sizePx": 24,
      "color": "#FFD700",
      "opacity": 0.9,
      "onlyOnClicks": false,
      "clickEmphasisDurationMs": 350,
      "offsetXNorm": 0,
      "offsetYNorm": 0
    }
  },
  "recentLogs": []
}

Video (if applicable):

<video src="path/to/video.mp4" controls width="600"></video>

Testing

Checklist

  • I have performed a self-review of my code.
  • I have added any necessary screenshots or videos.
  • I have linked related issue(s) and updated the changelog if applicable.

Thank you for contributing!

Summary by CodeRabbit

New Features

  • Added a "Save Diagnostics" button in the settings panel to export diagnostic information including errors, project state, and system logs to a JSON file.
  • Diagnostic exports automatically include app version, platform details, OS information, and memory statistics to assist with troubleshooting and support inquiries.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Adds end-to-end diagnostic save capability: IPC handler collects system metadata and writes JSON diagnostics to disk via save dialog; preload bridge exposes the API to renderers; TypeScript types define the contract; SettingsPanel conditionally renders a "Save Diagnostics" button wired through VideoEditor to capture current error state and editor snapshot.

Changes

Diagnostic Save Feature

Layer / File(s) Summary
Type Definitions
electron/electron-env.d.ts
Declares saveDiagnostic(payload) method signature on window.electronAPI, accepting diagnostic payload with error/stack/projectState/logs and returning promise with success/path/canceled/error fields.
IPC Handler
electron/ipc/handlers.ts
Adds os import and new save-diagnostic IPC handler that opens save dialog, constructs JSON diagnostic with system metadata (OS release, memory, app/Node/Electron/Chrome versions), writes to disk, and returns success/cancel/error result.
Preload Bridge
electron/preload.ts
Exposes saveDiagnostic(payload) on contextBridge.exposeInMainWorld("electronAPI", ...) to route renderer calls to main process via ipcRenderer.invoke("save-diagnostic", payload).
UI Components
src/components/video-editor/SettingsPanel.tsx, src/components/video-editor/VideoEditor.tsx
SettingsPanel props add optional onSaveDiagnostic callback; conditionally renders "Save Diagnostics" button with FileDown icon when callback provided. VideoEditor implements handler that invokes window.electronAPI.saveDiagnostic with current error/editorState/empty logs, shows success/error toast on completion.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🔧 when errors strike at 2am and chaos fills the screen,
a button blooms with hope—"save diagnostics, please"—
through preload bridges & IPC gates it goes,
metadata gathered like breadcrumbs, the whole truth laid bare. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly describes the main feature: adding a diagnostics report capability spanning type definitions, IPC handlers, preload, and UI components.
Description check ✅ Passed Description covers purpose and motivation with visual examples, but testing steps and several checklist items remain incomplete or unchecked.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
electron/ipc/handlers.ts (1)

1328-1332: ⚡ Quick win

nit: reuse buildDialogOptions here for consistency.

Small thing, but using the shared dialog helper keeps parent-window behavior aligned with the rest of the IPC handlers and avoids drift later.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/ipc/handlers.ts` around lines 1328 - 1332, The save dialog call uses
an inline options object instead of the shared helper; replace the inline
options passed to dialog.showSaveDialog in the handler (the block creating
defaultPath "openscreen-diagnostic-...") with a call to buildDialogOptions(...)
so it returns the same options shape (pass title, defaultPath, and filters into
buildDialogOptions) and then pass that result to dialog.showSaveDialog to
preserve consistent parent-window behavior across IPC handlers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@electron/ipc/handlers.ts`:
- Around line 1322-1361: Wrap the entire "save-diagnostic" ipcMain.handle
handler body in a top-level try/catch so any exceptions (e.g. from
dialog.showSaveDialog) are caught and the IPC always returns the expected object
shape; inside the catch, log the error (console.error) and return an object like
{ success: false, error: String(error), canceled: false } (or include canceled
if relevant) instead of letting the promise reject. Keep the existing inner
try/catch for fs.writeFile but move/encapsulate everything
(dialog.showSaveDialog, diagnostic construction, and writeFile call) into the
outer try block in the "save-diagnostic" handler to ensure callers always
receive a consistent response.

In `@src/components/video-editor/SettingsPanel.tsx`:
- Around line 1688-1697: The hardcoded button label "Save Diagnostics" in
SettingsPanel should be replaced with a localized string; locate the button
rendered when onSaveDiagnostic is present (the <button> using FileDown and
onSaveDiagnostic) and call the project's i18n helper (e.g., t('...') or
useTranslation/Trans) instead of the literal text, and add a matching locale key
like "settings.saveDiagnostics" to the translation files so the label is
translated consistently across locales.

In `@src/components/video-editor/VideoEditor.tsx`:
- Around line 1733-1744: The hardcoded strings in handleSaveDiagnostic (the
error fallback "Manual diagnostic export" and the toast messages passed to
toast.success/toast.error) must be localized: import or use the project's
translation helper (e.g., useTranslation()/t) and replace the literal strings
passed to window.electronAPI.saveDiagnostic (error), toast.success, and
toast.error with translated keys (e.g., t('diagnostics.manualExport'),
t('diagnostics.saveSuccess'), t('diagnostics.saveFailure')); keep exportError
fallback logic but use t(...) for the default message and update any existing
translation files with the new keys.

---

Nitpick comments:
In `@electron/ipc/handlers.ts`:
- Around line 1328-1332: The save dialog call uses an inline options object
instead of the shared helper; replace the inline options passed to
dialog.showSaveDialog in the handler (the block creating defaultPath
"openscreen-diagnostic-...") with a call to buildDialogOptions(...) so it
returns the same options shape (pass title, defaultPath, and filters into
buildDialogOptions) and then pass that result to dialog.showSaveDialog to
preserve consistent parent-window behavior across IPC handlers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 704e031e-624e-42e0-9002-cf8103020736

📥 Commits

Reviewing files that changed from the base of the PR and between 899504f and a0c423d.

📒 Files selected for processing (5)
  • electron/electron-env.d.ts
  • electron/ipc/handlers.ts
  • electron/preload.ts
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/VideoEditor.tsx

Comment thread electron/ipc/handlers.ts
Comment on lines +1322 to +1361
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) };
}
},
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard the whole diagnostic IPC flow with a top-level try/catch.

Right now, failures from showSaveDialog can reject the IPC call instead of returning the expected object shape. that’s kinda cursed for caller handling paths.

💡 Suggested patch
  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 {
+ 			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,
+ 			};
+
  			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) };
  		}
  	},
  );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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) };
}
},
);
ipcMain.handle(
"save-diagnostic",
async (
_,
payload: { error: string; stack?: string; projectState: unknown; logs: string[] },
) => {
try {
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,
};
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) };
}
},
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/ipc/handlers.ts` around lines 1322 - 1361, Wrap the entire
"save-diagnostic" ipcMain.handle handler body in a top-level try/catch so any
exceptions (e.g. from dialog.showSaveDialog) are caught and the IPC always
returns the expected object shape; inside the catch, log the error
(console.error) and return an object like { success: false, error:
String(error), canceled: false } (or include canceled if relevant) instead of
letting the promise reject. Keep the existing inner try/catch for fs.writeFile
but move/encapsulate everything (dialog.showSaveDialog, diagnostic construction,
and writeFile call) into the outer try block in the "save-diagnostic" handler to
ensure callers always receive a consistent response.

Comment on lines +1688 to +1697
{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>
)}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Button label should go through i18n.

Save Diagnostics is currently hardcoded, so this one string won’t localize with the rest of the panel.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/video-editor/SettingsPanel.tsx` around lines 1688 - 1697, The
hardcoded button label "Save Diagnostics" in SettingsPanel should be replaced
with a localized string; locate the button rendered when onSaveDiagnostic is
present (the <button> using FileDown and onSaveDiagnostic) and call the
project's i18n helper (e.g., t('...') or useTranslation/Trans) instead of the
literal text, and add a matching locale key like "settings.saveDiagnostics" to
the translation files so the label is translated consistently across locales.

Comment on lines +1733 to +1744
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]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Please localize the new diagnostic strings.

Right now "Manual diagnostic export" and the success/failure toasts are hardcoded English. lowkey breaks localization consistency in an otherwise fully translated screen.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/video-editor/VideoEditor.tsx` around lines 1733 - 1744, The
hardcoded strings in handleSaveDiagnostic (the error fallback "Manual diagnostic
export" and the toast messages passed to toast.success/toast.error) must be
localized: import or use the project's translation helper (e.g.,
useTranslation()/t) and replace the literal strings passed to
window.electronAPI.saveDiagnostic (error), toast.success, and toast.error with
translated keys (e.g., t('diagnostics.manualExport'),
t('diagnostics.saveSuccess'), t('diagnostics.saveFailure')); keep exportError
fallback logic but use t(...) for the default message and update any existing
translation files with the new keys.

@siddharthvaddem siddharthvaddem merged commit b525571 into siddharthvaddem:main May 8, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants