The server stores a registry write at once but only applies most settings when it rebuilds its configuration. It does that on a write for directories and the default authentication alone. An admin who saved a new delivery schedule saw nothing change until they ran Management → Actions → Reload → Server settings by hand.
What changes
Every x:<Type>/set passes a listener in the JMAP client (src/services/jmap/client.ts). That covers the generic form (DynamicForm), list bulk edits and deletes (DynamicList), and the custom pages (DNS connect, Local AI) without touching each one.
A write to a settings object queues the reload action it needs (src/lib/settingsApply.ts). Certificates, lookup stores and blocked IPs get their own reload actions, because the full settings reload doesn't rebuild them. Everything else that is settings gets ReloadSettings.
These get no reload:
directories and authentication, which the server reloads on write
data read live or kept current by cache invalidation: accounts, domains, DKIM keys, tenants, roles, lists, masked email, OAuth clients, public keys
operations and records: actions, tasks, the queue, reports, traces
stores, which a reload never reopens, so "applied" would be untrue
A type the list doesn't know is reloaded.
Saves are debounced (src/stores/settingsApplyStore.ts). The queued actions go out together in one x:Action/set once no write has been in flight for 600 ms, so a bulk edit costs one reload. A save still in flight holds the reload back.
Success: a "Saved and applied" toast. For settings objects it replaces the form's "Saved successfully" / "Created successfully", so there is one message rather than two.
Failure: a persistent banner above the page (src/components/layout/SettingsApplyBanner.tsx) that reads "Saved, but the server couldn't apply the settings: ". It names the object the server couldn't build, links to it, and has an Apply now button and a dismiss. It stays until a reload succeeds. A known failure is not retried on unrelated saves (an account edit, say), only on Apply now or on a save that needs a reload.
Why automatic rather than an "apply now" banner everywhere
A reload is all or nothing. The new configuration replaces the running one only when every settings object builds. Otherwise the server keeps what it had and returns validationFailed, naming the object. That means applying straight after a save can't leave the server half configured. The worst case is the failure banner, which is the same thing a manual reload would have shown. I found no page where an automatic reload is unsafe, so no page gets the manual-only banner.
If the server later applies these writes itself, this sends one extra, harmless reload per burst of saves, not one per object.
An account without the reload permission gets the failure banner with the server's permission message. That is accurate, because the settings really didn't apply.
Strings
New strings live in src/i18n/en.json, under settingsApply: applied, applyNow, dismiss, failed, failedObject, noAnswer, notConfirmed, openObject, stillRunning. English is the only catalogue this repo ships, so there are no other languages to add.
Checks
npm run typecheck && npm run lint && npm test && npm run build all pass: 21 test files, 354 tests. The new tests are src/lib/settingsApply.test.ts and src/stores/settingsApplyStore.test.ts. They cover:
classification of object types
response parsing
the debounce and holding back while a save is in flight
one reload for a burst of saves
how a failure is reported: object and message, request errors, method errors
retry rules and dismiss
Not yet exercised against a running server in a browser.
## Why
The server stores a registry write at once but only applies most settings when it rebuilds its configuration. It does that on a write for directories and the default authentication alone. An admin who saved a new delivery schedule saw nothing change until they ran **Management → Actions → Reload → Server settings** by hand.
## What changes
- **Every `x:<Type>/set` passes a listener in the JMAP client** (`src/services/jmap/client.ts`). That covers the generic form (`DynamicForm`), list bulk edits and deletes (`DynamicList`), and the custom pages (DNS connect, Local AI) without touching each one.
- **A write to a settings object queues the reload action it needs** (`src/lib/settingsApply.ts`). Certificates, lookup stores and blocked IPs get their own reload actions, because the full settings reload doesn't rebuild them. Everything else that is settings gets `ReloadSettings`.
- **These get no reload:**
- directories and authentication, which the server reloads on write
- data read live or kept current by cache invalidation: accounts, domains, DKIM keys, tenants, roles, lists, masked email, OAuth clients, public keys
- operations and records: actions, tasks, the queue, reports, traces
- stores, which a reload never reopens, so "applied" would be untrue
A type the list doesn't know is reloaded.
- **Saves are debounced** (`src/stores/settingsApplyStore.ts`). The queued actions go out together in one `x:Action/set` once no write has been in flight for 600 ms, so a bulk edit costs one reload. A save still in flight holds the reload back.
- **Success:** a "Saved and applied" toast. For settings objects it replaces the form's "Saved successfully" / "Created successfully", so there is one message rather than two.
- **Failure:** a persistent banner above the page (`src/components/layout/SettingsApplyBanner.tsx`) that reads *"Saved, but the server couldn't apply the settings: <reason>"*. It names the object the server couldn't build, links to it, and has an **Apply now** button and a dismiss. It stays until a reload succeeds. A known failure is not retried on unrelated saves (an account edit, say), only on Apply now or on a save that needs a reload.
## Why automatic rather than an "apply now" banner everywhere
A reload is all or nothing. The new configuration replaces the running one only when every settings object builds. Otherwise the server keeps what it had and returns `validationFailed`, naming the object. That means applying straight after a save can't leave the server half configured. The worst case is the failure banner, which is the same thing a manual reload would have shown. I found no page where an automatic reload is unsafe, so no page gets the manual-only banner.
If the server later applies these writes itself, this sends one extra, harmless reload per burst of saves, not one per object.
An account without the reload permission gets the failure banner with the server's permission message. That is accurate, because the settings really didn't apply.
## Strings
New strings live in `src/i18n/en.json`, under `settingsApply`: `applied`, `applyNow`, `dismiss`, `failed`, `failedObject`, `noAnswer`, `notConfirmed`, `openObject`, `stillRunning`. English is the only catalogue this repo ships, so there are no other languages to add.
## Checks
`npm run typecheck && npm run lint && npm test && npm run build` all pass: 21 test files, 354 tests. The new tests are `src/lib/settingsApply.test.ts` and `src/stores/settingsApplyStore.test.ts`. They cover:
- classification of object types
- response parsing
- the debounce and holding back while a save is in flight
- one reload for a burst of saves
- how a failure is reported: object and message, request errors, method errors
- retry rules and dismiss
Not yet exercised against a running server in a browser.
A registry write is stored at once, but the running server only picks up
most settings when it rebuilds its configuration, which it does on a write
for directories and the default authentication alone. Everything else, a
delivery schedule for one, sat unapplied until someone ran Management >
Actions > Reload > Server settings by hand.
Every x:<Type>/set now goes past a listener in the JMAP client. A write that
changed a settings object queues the reload action it needs, and once no
write has been in flight for 600 ms the queued actions go out together in
one x:Action/set. A bulk edit or a page that saves several objects in a row
costs one reload, not one per object; a save still in flight holds the
reload back however long it takes.
Which action a type needs lives in lib/settingsApply.ts. Certificates, lookup
stores and blocked IPs have their own reload actions, and the full settings
reload doesn't rebuild them. Directories and authentication, data read live
or kept current by cache invalidation (accounts, domains, DKIM keys, tenants,
roles, lists and the like), operations and records, and stores, which a
reload never reopens, get none. A type the list doesn't know is reloaded: an
unneeded reload costs a second, a missing one leaves a setting unapplied. If
the server later applies these writes by itself, this becomes one extra,
harmless reload per burst of saves.
Applying straight after a save is safe because a reload is all or nothing:
the new configuration replaces the running one only when every settings
object builds. When one doesn't, the server keeps what it had and names the
object and the problem. That now shows as a banner above the page, "Saved,
but the server couldn't apply the settings: <reason>", naming the object with
a link to it, and an Apply now button. It stays until a reload succeeds or it
is dismissed. A failure that is already known is not retried on unrelated
saves, only on Apply now or a save that needs a reload.
On success a "Saved and applied" toast replaces the form's own "Saved
successfully" and "Created successfully" for settings objects, so a save
shows one message, not two.
New strings, in src/i18n/en.json (the only catalogue) under settingsApply:
applied, applyNow, dismiss, failed, failedObject, noAnswer, notConfirmed,
openObject, stillRunning.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Why
The server stores a registry write at once but only applies most settings when it rebuilds its configuration. It does that on a write for directories and the default authentication alone. An admin who saved a new delivery schedule saw nothing change until they ran Management → Actions → Reload → Server settings by hand.
What changes
Every
x:<Type>/setpasses a listener in the JMAP client (src/services/jmap/client.ts). That covers the generic form (DynamicForm), list bulk edits and deletes (DynamicList), and the custom pages (DNS connect, Local AI) without touching each one.A write to a settings object queues the reload action it needs (
src/lib/settingsApply.ts). Certificates, lookup stores and blocked IPs get their own reload actions, because the full settings reload doesn't rebuild them. Everything else that is settings getsReloadSettings.These get no reload:
A type the list doesn't know is reloaded.
Saves are debounced (
src/stores/settingsApplyStore.ts). The queued actions go out together in onex:Action/setonce no write has been in flight for 600 ms, so a bulk edit costs one reload. A save still in flight holds the reload back.Success: a "Saved and applied" toast. For settings objects it replaces the form's "Saved successfully" / "Created successfully", so there is one message rather than two.
Failure: a persistent banner above the page (
src/components/layout/SettingsApplyBanner.tsx) that reads "Saved, but the server couldn't apply the settings: ". It names the object the server couldn't build, links to it, and has an Apply now button and a dismiss. It stays until a reload succeeds. A known failure is not retried on unrelated saves (an account edit, say), only on Apply now or on a save that needs a reload.Why automatic rather than an "apply now" banner everywhere
A reload is all or nothing. The new configuration replaces the running one only when every settings object builds. Otherwise the server keeps what it had and returns
validationFailed, naming the object. That means applying straight after a save can't leave the server half configured. The worst case is the failure banner, which is the same thing a manual reload would have shown. I found no page where an automatic reload is unsafe, so no page gets the manual-only banner.If the server later applies these writes itself, this sends one extra, harmless reload per burst of saves, not one per object.
An account without the reload permission gets the failure banner with the server's permission message. That is accurate, because the settings really didn't apply.
Strings
New strings live in
src/i18n/en.json, undersettingsApply:applied,applyNow,dismiss,failed,failedObject,noAnswer,notConfirmed,openObject,stillRunning. English is the only catalogue this repo ships, so there are no other languages to add.Checks
npm run typecheck && npm run lint && npm test && npm run buildall pass: 21 test files, 354 tests. The new tests aresrc/lib/settingsApply.test.tsandsrc/stores/settingsApplyStore.test.ts. They cover:Not yet exercised against a running server in a browser.