From a8e7669f5a38cbc7166b38a20a0a71af5e986dd3 Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Sun, 12 Jul 2026 19:58:23 +0200 Subject: [PATCH] fix(review): preserve shortcutOverrides across settings saves + keep help modal reachable (PR #146) - saveAppSettings() rebuilds settings from the DOM; carry over shortcutOverrides like showTokenCount/showCost so rebinding survives unrelated saves - shortcut overlay footer links to the full help modal (its only opener was the legacy Ctrl+? route this PR replaced) Co-Authored-By: Claude Fable 5 --- src/web/public/index.html | 3 +++ src/web/public/settings-ui.js | 3 +++ src/web/public/styles.css | 7 +++++++ test/shortcut-registry-overlay.test.ts | 16 ++++++++++++++++ 4 files changed, 29 insertions(+) diff --git a/src/web/public/index.html b/src/web/public/index.html index b48e4c08..f8ad5c46 100644 --- a/src/web/public/index.html +++ b/src/web/public/index.html @@ -1679,6 +1679,9 @@ diff --git a/src/web/public/settings-ui.js b/src/web/public/settings-ui.js index 3e8fd626..366e89ad 100644 --- a/src/web/public/settings-ui.js +++ b/src/web/public/settings-ui.js @@ -1458,6 +1458,9 @@ Object.assign(CodemanApp.prototype, { // with no UI left to turn it back off. Preserve the prior stored preference. if (_prev.showTokenCount !== undefined) settings.showTokenCount = _prev.showTokenCount; if (_prev.showCost !== undefined) settings.showCost = _prev.showCost; + // Shortcut overrides are edited from the Shortcuts tab (not rebuilt from the + // general-settings DOM), so the fresh rebuild would drop them on every save. + if (_prev.shortcutOverrides !== undefined) settings.shortcutOverrides = _prev.shortcutOverrides; // Save to localStorage this.saveAppSettingsToStorage(settings); diff --git a/src/web/public/styles.css b/src/web/public/styles.css index ea5dbc07..68dd0731 100644 --- a/src/web/public/styles.css +++ b/src/web/public/styles.css @@ -5812,6 +5812,13 @@ kbd { color: var(--text-dim); } +.shortcut-overlay-footer { + margin-top: 0.75rem; + padding-top: 0.75rem; + border-top: 1px solid var(--border); + text-align: right; +} + .away-digest-ranges { display: flex; flex-wrap: wrap; diff --git a/test/shortcut-registry-overlay.test.ts b/test/shortcut-registry-overlay.test.ts index 014c9468..24b63301 100644 --- a/test/shortcut-registry-overlay.test.ts +++ b/test/shortcut-registry-overlay.test.ts @@ -59,6 +59,22 @@ describe('shortcut registry and overlay', () => { expect(css).toContain('.shortcut-capture-btn,'); expect(css).toContain('.shortcut-overlay-row {'); }); + + it('saveAppSettings preserves shortcutOverrides (rebuilt-from-DOM saves must not wipe them)', () => { + // Same trap as showTokenCount/showCost: saveAppSettings() rebuilds the settings + // object fresh from the DOM, so keys edited elsewhere (the Shortcuts tab) must be + // explicitly carried over from the previously stored blob. + expect(settingsSource).toContain( + 'if (_prev.shortcutOverrides !== undefined) settings.shortcutOverrides = _prev.shortcutOverrides;' + ); + }); + + it('keeps the full help modal reachable now that Ctrl+? opens the registry overlay', () => { + // The legacy #helpModal (full shortcut reference) lost its only opener when + // Ctrl+? was rerouted to the overlay; the overlay footer must link to it. + expect(htmlSource).toContain('shortcut-overlay-footer'); + expect(htmlSource).toContain('app.closeShortcutOverlay(); app.showHelp()'); + }); }); // ─── Functional coverage (vm-sandbox harness, mirrors run-mode-ui.test.ts) ────