From cc2f9ef3255ac83a8c56656c5bc5710e776fd313 Mon Sep 17 00:00:00 2001 From: sudacode Date: Fri, 27 Feb 2026 18:33:36 -0800 Subject: [PATCH] fix(macos): show full config warning details --- src/main/config-validation.test.ts | 17 +++++++++++++++++ src/main/config-validation.ts | 19 +++++++++++++++++++ src/main/runtime/startup-config.test.ts | 6 ++++++ src/main/runtime/startup-config.ts | 7 +++++++ 4 files changed, 49 insertions(+) diff --git a/src/main/config-validation.test.ts b/src/main/config-validation.test.ts index f9aa870..14e5044 100644 --- a/src/main/config-validation.test.ts +++ b/src/main/config-validation.test.ts @@ -2,6 +2,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { buildConfigParseErrorDetails, + buildConfigWarningDialogDetails, buildConfigWarningNotificationBody, buildConfigWarningSummary, failStartupFromConfig, @@ -53,6 +54,22 @@ test('buildConfigWarningNotificationBody includes concise warning details', () = ); }); +test('buildConfigWarningDialogDetails includes full warning details', () => { + const details = buildConfigWarningDialogDetails('/tmp/config.jsonc', [ + { + path: 'ankiConnect.pollingRate', + message: 'must be >= 50', + value: 10, + fallback: 250, + }, + ]); + + assert.match(details, /SubMiner detected config validation issues\./); + assert.match(details, /File: \/tmp\/config\.jsonc/); + assert.match(details, /1\. ankiConnect\.pollingRate: must be >= 50/); + assert.match(details, /actual=10 fallback=250/); +}); + test('buildConfigParseErrorDetails includes path error and restart guidance', () => { const details = buildConfigParseErrorDetails('/tmp/config.jsonc', 'unexpected token at line 1'); diff --git a/src/main/config-validation.ts b/src/main/config-validation.ts index a9c326f..b0bde54 100644 --- a/src/main/config-validation.ts +++ b/src/main/config-validation.ts @@ -61,6 +61,25 @@ export function buildConfigWarningNotificationBody( ].join('\n'); } +export function buildConfigWarningDialogDetails( + configPath: string, + warnings: ConfigValidationWarning[], +): string { + const lines = warnings.map( + (warning, index) => + `${index + 1}. ${warning.path}: ${warning.message} actual=${formatConfigValue(warning.value)} fallback=${formatConfigValue(warning.fallback)}`, + ); + + return [ + 'SubMiner detected config validation issues.', + `File: ${configPath}`, + '', + ...lines, + '', + 'Defaults were applied where possible.', + ].join('\n'); +} + export function buildConfigParseErrorDetails(configPath: string, parseError: string): string { return [ 'Failed to parse config file at:', diff --git a/src/main/runtime/startup-config.test.ts b/src/main/runtime/startup-config.test.ts index 742ece7..a6fa17b 100644 --- a/src/main/runtime/startup-config.test.ts +++ b/src/main/runtime/startup-config.test.ts @@ -42,6 +42,12 @@ test('createReloadConfigHandler runs success flow with warnings', async () => { calls.some((entry) => entry.includes('notify:SubMiner:1 config validation issue(s) detected.')), ); assert.ok(calls.some((entry) => entry.includes('1. ankiConnect.pollingRate: must be >= 50'))); + assert.ok( + calls.some((entry) => + entry.includes('dialog:SubMiner config validation warning:SubMiner detected config validation issues.'), + ), + ); + assert.ok(calls.some((entry) => entry.includes('actual=10 fallback=250'))); assert.ok(calls.includes('hotReload:start')); assert.deepEqual(refreshCalls, [{ force: true }]); }); diff --git a/src/main/runtime/startup-config.ts b/src/main/runtime/startup-config.ts index 74f26e6..b735139 100644 --- a/src/main/runtime/startup-config.ts +++ b/src/main/runtime/startup-config.ts @@ -1,5 +1,6 @@ import type { ConfigValidationWarning } from '../../types'; import { + buildConfigWarningDialogDetails, buildConfigParseErrorDetails, buildConfigWarningNotificationBody, buildConfigWarningSummary, @@ -60,6 +61,12 @@ export function createReloadConfigHandler(deps: ReloadConfigRuntimeDeps): () => deps.showDesktopNotification('SubMiner', { body: buildConfigWarningNotificationBody(result.path, result.warnings), }); + if (process.platform === 'darwin') { + deps.failHandlers.showErrorBox( + 'SubMiner config validation warning', + buildConfigWarningDialogDetails(result.path, result.warnings), + ); + } } deps.startConfigHotReload();