Skip to content

fix(settings): report a fully denied Settings Save as one failure - #1355

Merged
IAmJSD merged 1 commit into
LeanerCloud:mainfrom
IAmJSD:ui/issue-617
Oct 24, 2026
Merged

IAmJSD merged 1 commit into
LeanerCloud:mainfrom
IAmJSD:ui/issue-617

Conversation

@IAmJSD

@IAmJSD IAmJSD commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator

Since #614, the per-service config PUTs need unrestricted account scope, like the global config PUT. A scoped admin can still click Save, which fires all 17 service PUTs; every one returns 403, and the toast read "Settings saved, but 17 services failed:" followed by the same denial 17 times, even though nothing was saved. This PR shows one "Failed to save settings: permission denied: ..." toast in that case, and only says "Settings saved, but ..." when something actually saved.

Closes #617

What changed

Why this approach

The issue offers three options. Mapping permission-denied results to one failure toast is the smallest change and leaves the save and dirty-tracking flow alone. Skipping unchanged service PUTs would change what Save writes, which interacts with coverage propagation and the #539 stale-write handling (and the existing test pins 17 calls). Hiding or disabling settings for scoped users would need the session to expose account scope, which the frontend can't see today. The extra "nothing saved, other errors" branch fixes the same false "Settings saved" claim for non-permission failures.

Screenshots

Before is main (a14dc8f2), after is this branch. Both are headless Chromium at 1440x900 against the repo's mocked e2e API. The scenario is Admin > Purchasing policies with every config PUT mocked to 403, after changing the EC2 payment and clicking Save.

Before After
scoped-admin-save before scoped-admin-save after
  • Before: "Settings saved, but 17 services failed:" with the same permission-denied reason repeated 17 times, filling the screen. After: one toast, "Failed to save settings: permission denied: global configuration requires unrestricted account access".

Verification

Run on this branch's head a89a19cd on top of main a14dc8f2:

  • Lint: 0 errors (142 existing warnings). Typecheck and build pass.
  • Jest: 109 suites, 3489 passed, 1 skipped. New tests: (1) scoped admin, all service PUTs 403 and no global change, gives exactly one toast "Failed to save settings: permission denied: ..." with the edited card still dirty; (2) all PUTs fail with mixed errors gives "Failed to save settings: 17 services failed: ..."; (3) global saved but all services fail still gives "Settings saved, but 17 services failed". Tests 1 and 2 fail on main a14dc8f2 and pass here. Randomized run: 18/18.
  • Playwright: 157 passed. No new spec (toast copy only; jest covers it).
  • git-secrets scan clean (planted key flagged); allowlist test 137 pass.

Notes for review

  • The denied case reuses the backend message verbatim ("permission denied: global configuration requires unrestricted account access"), so it matches the global-PUT toast word for word.
  • Root cause left in place: a scoped admin still sees an enabled Save on these settings. Disabling it properly needs the backend to expose the session's account scope (for example in /auth/me).
  • Mixed case (some services denied, some fine) still lists each denied service, which is accurate because some services did save.

Overlaps

Other branches edit settings.ts in different regions only (#186 near line 3170, #734 near lines 1348-1509, #731, #728, #748), so no textual conflicts with the saveGlobalSettings hunk (about lines 3550-3700) are expected. #642 also edits settings.ts around Reset/reload and should be checked when combining. Those PRs will be opened alongside this one and merged in sequence, with conflicts resolved on the later branch.

Note for the UI owner

This changes UI code that @cristim owns. IAmJSD reviewed the before/after screenshots and asked for it to be merged; any design point you disagree with can be a follow-up.

🤖 Generated with Claude Code

…t 17

Since LeanerCloud#614 gated per-service config PUTs on unrestricted account scope, a
scoped admin's Save fires all 17 service PUTs and every one returns 403.
Promise.allSettled kept the save going, and the toast read "Settings
saved, but 17 services failed: <same denial x17>" even though nothing was
saved.

Only say "Settings saved, but ..." when something did save (the global
PUT went out or at least one service PUT succeeded). When nothing saved
and every service PUT was permission-denied, show the backend's single
reason in the same "Failed to save settings: permission denied: ..."
form the global PUT already uses. When nothing saved for other reasons,
say the save failed and list the services. The dirty-snapshot handling
is unchanged: failed services keep their fields dirty for a retry.

Refs LeanerCloud#617

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@IAmJSD IAmJSD added triaged Item has been triaged priority/p3 Polish / idea / may never ship severity/low Minor harm urgency/this-quarter Within the quarter impact/few Limited audience effort/s Hours type/bug Defect labels Oct 24, 2026
@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 2 billable files and costs up to $0.50.

Or wait 59 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between 61be5b6 and a89a19c.

Files selected for processing: 2
  • frontend/src/__tests__/settings-service-payment.test.ts
  • frontend/src/settings.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@IAmJSD

IAmJSD commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): APPROVE a89a19cd31a509f093163e7a979fa44b5d18f014

Blocking:

  • none
    Non-blocking:
  • The "global saved, every service denied" branch still lists 17 identical denials. It is unreachable for a scoped admin, because the global PUT 403s first and goes to the catch toast.
    Attacked: Walked saveGlobalSettings with globalSent false or true, all services fulfilled, rejected or mixed, and checked serviceSaveFailureMessage's savedSomething logic. reasons[0] is safe when every result is a rejected permission error (isPermissionDeniedError requires an Error with status 403 and a "permission denied" prefix). Confirmed defaultCoverageChanged implies globalSent. The snapshot and dirty-revert logic is untouched, and the new tests assert one toast with the card still dirty. "Closes fix(settings): a scoped admin's Settings Save shows 'Settings saved, but 17 services failed' after service-config PUTs became scope-gated #617" matches the acceptance criteria (one clear message plus a jest test).

@IAmJSD

IAmJSD commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

Local verification at a89a19cd merged onto current main (8e9aa9f7; merge-tree 6510d94e; Linux, Node, headless Chromium):

  • This branch's own checks passed at this head: lint, typecheck, build, the full jest suite, the full Playwright e2e suite, and the git-secrets checks (see Verification in the PR body).
  • The combined tree of every UI PR in this merge wave (tree 89dd34d8, main plus 46 PRs) passes npm ci, lint, typecheck, build, jest (1 skipped, 3914 passed, 3915 total), and the full Playwright suite (208 passed).
  • CI is green on a89a19cd (CI Success, Run pre-commit hooks).
  • The independent review above approves this exact head.
  • Nothing was applied to any cloud.

@IAmJSD
IAmJSD marked this pull request as ready for review October 24, 2026 15:49
@IAmJSD
IAmJSD merged commit 84a7f35 into LeanerCloud:main Oct 24, 2026
29 checks passed
@IAmJSD

IAmJSD commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

Marked ready and merged by IAmJSD's agent, at IAmJSD's request (IAmJSD reviewed the before/after screenshots; cristim is traveling), after the independent review and local verification above, all at a89a19cd.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/s Hours impact/few Limited audience priority/p3 Polish / idea / may never ship severity/low Minor harm triaged Item has been triaged type/bug Defect urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(settings): a scoped admin's Settings Save shows 'Settings saved, but 17 services failed' after service-config PUTs became scope-gated

1 participant