fix: warn before the delete, not after — plus round-2 copy and a11y corrections
Round 2 on the feature diff (15 → 12): - still_allowed_by_env now rides the invite LIST as well as the delete response, so the confirmation warns while the admin can still change their mind. It mattered most for a DENIED row on an env-allow-listed address: deleting it silently converted a refusal into a grant, and the only warning arrived after the irreversible click. - Both inbox bodies claimed to name "the most recent" dropped message. The throttle records the FIRST of each hour and never updates it, so they now say "one of them", and the not-configured body finally names where to fix it. - settings.invites.emailOff told the admin they "get no notice when someone signs up" — rendered directly above the queue that shows exactly that. Only the email is lost, and it now says so. - The disabled delete buttons put their reason out of reach: `disabled` drops a control from the tab order and suppresses its title. Switched to aria-disabled + preventDefault, the pattern Playlists.tsx already established for the same reason. - deleteInvite is quiet, so the 409 the UI handles with a translated toast no longer also raises the server's English detail as a modal. - After a completed password reset, Back landed on the reset form again with a consumed token — the history change made that state reachable. The token is cleared on success so the reset view stops being the card's root. - The hu deleteHasAccount named a tab that renders under a different label. Tests: a dom test for the Access-requests panel covering both has_account variants and all three delete outcomes, /api/me flag cases, an ADMIN_EMAILS case, and the env-allowlist test now patches the raw setting so the parsing stays under test.
This commit is contained in:
@@ -22,6 +22,9 @@ export interface Invite {
|
||||
/** An account already exists for this address, so the entry can't be deleted from here — deleting
|
||||
* it would revoke that user's access (is_allowed reads this row). Delete the user instead. */
|
||||
has_account: boolean;
|
||||
/** The address stays allow-listed by the server's env ALLOWED_EMAILS / ADMIN_EMAILS, so removing
|
||||
* this row would NOT take access away. The delete confirmation says so. */
|
||||
still_allowed_by_env: boolean;
|
||||
}
|
||||
|
||||
// Admin Configuration page: one DB-overridable setting (registry entry on the backend).
|
||||
@@ -174,6 +177,8 @@ export const adminApi = {
|
||||
req("/api/admin/invites", { method: "POST", body: JSON.stringify({ email }) }),
|
||||
/** `still_allowed_by_env` is true when the address stays allow-listed by the server's env
|
||||
* ALLOWED_EMAILS / ADMIN_EMAILS, i.e. removing the row did not actually revoke access. */
|
||||
// quiet: a 409 here ("that address has an account") is a case the UI handles with a translated
|
||||
// toast; without this the shared handler ALSO raises the server's English detail as a modal.
|
||||
deleteInvite: (id: number): Promise<{ deleted: number; still_allowed_by_env: boolean }> =>
|
||||
req(`/api/admin/invites/${id}`, { method: "DELETE" }),
|
||||
req(`/api/admin/invites/${id}`, { method: "DELETE" }, { quiet: true }),
|
||||
};
|
||||
|
||||
@@ -20,8 +20,8 @@ export const RELEASE_NOTES: ReleaseEntry[] = [
|
||||
summary:
|
||||
"Admins can delete a whitelist entry, and an instance that cannot send email finally says so — in the inbox when a message is dropped, and on the screens where it matters.",
|
||||
features: [
|
||||
"Delete an entry under Users → Access requests: an address you whitelisted earlier, or a request nobody has acted on. Deny records your decision and keeps the record; delete forgets the address, and a later request from it arrives as a new one. Entries that already have an account behind them show the control disabled — that row is the account's approval gate, so it is managed from Users & roles, where deleting the account removes the entry too. If the address is also allow-listed in the server's configuration, the confirmation says so, because then removing the entry does not actually take access away.",
|
||||
"When a message cannot go out, every admin gets it in their inbox, naming the most recent message that was lost — an access request, a verification link, a password reset. Sending is deliberately fail-soft so a mail problem never breaks sign-up, but that used to mean it left no trace anywhere. Throttled to one notice an hour, so a dead relay cannot bury the inbox.",
|
||||
"Delete an entry under Users → Access requests: an address you whitelisted earlier, or a request nobody has acted on. Deny records your decision and keeps the record; delete forgets the address, and a later request from it arrives as a new one. Entries that already have an account behind them show the control disabled — that row is the account's approval gate, so it is managed from Users & roles, where deleting the account removes the entry too. If the address is also allow-listed in the server's configuration, the confirmation warns you before you commit, because then removing the entry does not actually take access away.",
|
||||
"When a message cannot go out, every admin gets it in their inbox, naming one of the messages that were lost — an access request, a verification link, a password reset — so you know what your users did not get. Sending is deliberately fail-soft so a mail problem never breaks sign-up, but that used to mean it left no trace anywhere. Throttled to one notice an hour, so a dead relay cannot bury the inbox; the log keeps the full list.",
|
||||
"A standing warning where it can be acted on: on Configuration → Email / SMTP while the settings are incomplete, and above the access-request list, where it explains that nobody is getting a verification link and no request will reach you by email.",
|
||||
],
|
||||
fixes: [
|
||||
|
||||
Reference in New Issue
Block a user