fix: address the feature review — accurate copy, reachable controls, real coverage
Round 1 on the feature diff found 15; the substantive ones: - The delete control VANISHED on any invite whose address had registered, which is the ordinary sign-up shape (register writes the User and the pending invite together). The guard stays broad — that row is the account's approval gate, and orphaning it strands someone who can then neither sign in nor be approved — but the control is now a disabled button carrying the reason, on both lists, so an admin never sees a row silently missing a button its neighbours have. - Deleting an entry is not always a revoke: is_allowed falls back to the env ALLOWED_EMAILS / ADMIN_EMAILS lists once no row exists, and an ADMIN_EMAILS address is force-promoted on its next Google sign-in. The route now reports still_allowed_by_env and the UI says so instead of claiming access was removed. - "Deny keeps the row so they can't immediately re-ask" was simply false — upsert_pending_invite reopens a denied row. Corrected everywhere it was stated. - The Configuration warning reads me.email_configured, which save() did not invalidate, so it kept warning about fields the admin had just filled in. - The read-only variant was an aria-hidden span explained only by a Tooltip that the hints toggle can switch off; now a disabled button with title + aria-label. - The delete error path threw away the 409's reason (the stale-list case) and left the stale row on screen. - The throttle window was spent even when no notice was written, silencing the next hour on the path whose job is to stop silent drops. - email_enabled() opened a second session and decrypted the SMTP password on every /api/me poll; it now takes the caller's session. - welcomeMode.dom.test.ts never rendered the card, so reverting the history wiring to useState left it green. A render test now drives the real links and fails on that revert (verified). Plus /api/me flag tests, the registration-shaped pending case, the env-allowlist case, and a release note that matches what the code does.
This commit is contained in:
@@ -103,6 +103,10 @@ export default function ConfigPanel() {
|
||||
}
|
||||
}
|
||||
await qc.invalidateQueries({ queryKey: qk.adminConfig() });
|
||||
// The email-not-configured notice reads me.email_configured, which is otherwise only
|
||||
// refetched on its own 60s interval — without this it keeps warning about fields the admin
|
||||
// has just filled in, which reads as the save not having taken.
|
||||
await qc.invalidateQueries({ queryKey: qk.me() });
|
||||
setReseedToken((n) => n + 1); // re-seed the draft from the saved server state
|
||||
setSaveState("saved");
|
||||
setTimeout(() => setSaveState((s) => (s === "saved" ? "idle" : s)), 2500);
|
||||
|
||||
Reference in New Issue
Block a user