Skip to content

fix(admin): only prompt for unsaved changes when settings actually edited (closes #1441) - #1445

Merged
cristim merged 1 commit into
mainfrom
fix/1441-admin-false-unsaved-prompt
Jul 17, 2026
Merged

cristim merged 1 commit into
mainfrom
fix/1441-admin-false-unsaved-prompt

Conversation

@cristim

@cristim cristim commented Jul 17, 2026 •

Copy link
Copy Markdown
Member

Root cause

isUnsavedChanges() in settings.ts compared live DOM values against savedSnapshot, which starts as an empty object ({}) at module initialisation. loadGlobalSettings() is async -- it calls snapshotAllFields() only after the API response arrives and all fields are populated. During the async window between the navigation-guard being armed and the snapshot being populated, every comparison was getFieldValue(id) !== undefined which is always true. This caused the "You have unsaved settings changes. Leave without saving?" modal to fire on every Admin-tab navigation, for all roles including read-only viewers who had made no edits.

Fix

Guard isUnsavedChanges() with Object.keys(savedSnapshot).length === 0 → return false. When the snapshot is empty the form is still loading and no edit is possible. After snapshotAllFields() runs (inside loadGlobalSettings() after all fields are populated), the snapshot is non-empty and dirty comparison proceeds normally.

Tests added (frontend/src/__tests__/settings.test.ts)

  1. Empty-snapshot regression test (via jest.isolateModules for a fresh module instance): fails with pre-fix code (undefined comparison returns true), passes with fix.
  2. Pristine load + navigate: isUnsavedChanges() returns false after loadGlobalSettings() with no user edits.
  3. Edit + navigate: isUnsavedChanges() returns true after a tracked field is mutated, confirming the fix does not suppress legitimate dirty detection.

Test plan

  • Run cd frontend && npx jest --no-coverage --testPathPattern="settings.test.ts" -- all 75 tests pass.
  • Verify npm run build succeeds.
  • Manual: visit Admin tab in browser, navigate away immediately without editing -- no prompt.
  • Manual: visit Admin tab, change a setting, navigate away -- prompt appears.

Closes #1441

Summary by CodeRabbit

  • Bug Fixes
    • Prevented unsaved-changes prompts from appearing before settings finish loading.
    • Navigation warnings now appear only after a loaded setting has been modified.
    • Improved handling of clipboard actions and confirmation dialogs in settings workflows.

…ited (closes #1441)

isUnsavedChanges() compared live DOM values against savedSnapshot, which
starts as an empty object ({}) before loadGlobalSettings() resolves. Since
any non-undefined DOM value differs from undefined, the comparison always
returned true, so the "You have unsaved settings changes. Leave without
saving?" prompt fired on every Admin-tab navigation -- even for read-only
users who had made no edits and even before the async settings load
completed.

Fix: guard with Object.keys(savedSnapshot).length === 0 at the top of
isUnsavedChanges(). When the snapshot is empty the form is still loading
and no edit is possible; return false immediately. snapshotAllFields()
(called inside the loadGlobalSettings() try block after all fields are
populated) sets the snapshot, enabling normal dirty-comparison for
subsequent checks.

Add three regression tests: the empty-snapshot path (via jest.isolateModules
to get a fresh module instance), pristine-load navigation (no prompt), and
edit-then-navigate (prompt shown correctly).
@cristim cristim added triaged Item has been triaged priority/p2 Backlog-worthy severity/medium Moderate harm urgency/this-sprint Within the current sprint impact/all-users Affects every user effort/s Hours type/bug Defect labels Jul 17, 2026
@cristim

cristim commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e40ecc78-d3e5-4d01-9c6d-b490eceabd55

📥 Commits

Reviewing files that changed from the base of the PR and between bef2d0e and 7bd6fe5.

📒 Files selected for processing (2)
  • frontend/src/__tests__/settings.test.ts
  • frontend/src/settings.ts

📝 Walkthrough

Walkthrough

The settings navigation guard now returns no unsaved-change state before settings loading completes. Tests cover fresh module state, a loaded unchanged form, and a modified tracked field, with deterministic confirmation and toast mocks.

Changes

Settings navigation guard

Layer / File(s) Summary
Guard snapshot initialization
frontend/src/settings.ts
isUnsavedChanges() returns false until savedSnapshot is populated, then compares tracked fields against the snapshot.
Navigation guard validation
frontend/src/__tests__/settings.test.ts
Tests cover pre-load, unchanged post-load, and edited post-load states, with controlled confirmation and toast mocks.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the fix for suppressing false unsaved-changes prompts when settings are not edited.
Linked Issues check ✅ Passed The code and tests address the no-edit prompt bug and preserve prompting after a real edit, matching #1441's acceptance criteria.
Out of Scope Changes check ✅ Passed The changes stay focused on the Admin unsaved-changes guard and its regression tests, with no clear unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/1441-admin-false-unsaved-prompt

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

@coderabbitai

coderabbitai Bot commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@cristim
cristim merged commit 73f4b54 into main Jul 17, 2026
20 checks passed
@cristim
cristim deleted the fix/1441-admin-false-unsaved-prompt branch July 27, 2026 11:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/s Hours impact/all-users Affects every user priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged type/bug Defect urgency/this-sprint Within the current sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(admin): false "unsaved settings changes" prompt when leaving Admin with no edits (all roles)

1 participant