* feat(admin): explain env-var substitution in /settings, surface auth errors (#7819)
Three small, env-var-only UX improvements driven by issue #7819, where a
Docker operator saved an ep_oauth block in the admin /settings raw view
and reported it "disappeared" — but the underlying confusion was that
settings.json on disk is a *template*, not the effective config. None of
these changes is visible to installs that don't use ${VAR} placeholders.
* Banner above the editor explaining the template/env-substitution model,
only rendered when the loaded file contains a ${VAR} placeholder. Tells
the operator that the file is not env-substituted in place and that the
Effective tab shows the live values.
* Effective tab in the mode toggle, read-only, also gated on ${VAR}. The
backend was already emitting redacted runtime settings as `resolved`
alongside every `load`; the SPA now exposes them so an operator can
verify what Etherpad is actually using.
* admin_auth_error event from the /settings socket handler. The handler
previously silently returned when the connecting session wasn't admin,
which made misrouted Traefik+SSO auth look like "save did nothing" with
no error path in the UI. Emit a dedicated event before dropping the
socket so the SPA can show a clear toast.
Tests:
- src/tests/backend/specs/admin/adminSettingsAuthError.ts — new spec for
the auth_error/disconnect contract.
- src/tests/frontend-new/admin-spec/adminsettings.spec.ts — new Playwright
test asserting the banner + Effective tab only appear after a ${VAR}
is added to settings.json, and that the Effective view is read-only +
shows [REDACTED] for secrets.
No behaviour change for installs without ${VAR} placeholders — banner,
Effective tab, and auth-error contract are all the same as before.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(admin): drop fragile pre-condition + add reconnect-loop guard (#7819)
CI's admin-UI workflow seeds settings.json by copying settings.json.template
verbatim, which contains ~30 \${VAR} placeholders. The new Playwright
test asserted "banner not present before adding placeholder" — true on a
fresh dev machine, false in CI. Drop that assertion: the negative path
is covered by the SettingsPage ENV_VAR_PATTERN regex itself; what
matters at the UI level is the positive path (banner + Effective tab
render correctly when placeholders are present), which this test still
exercises.
Also: the server's admin_auth_error path calls socket.disconnect(),
which the SPA's existing disconnect handler interprets as "io server
disconnect" and immediately reconnects — creating a reject/reconnect
loop. Track an authErrored flag and suppress the reconnect once an
auth_error has been received. Reset on successful connect, so a
legitimate re-auth path still works.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: spec for admin/settings resolved runtime values (#7803)
Side-channel resolved+redacted settings alongside raw file blob.
Form view dropdowns and env pill chips reflect actual runtime values
instead of falling back to template defaults. Save round-trip is
unchanged so ${VAR:default} literals stay intact on disk.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: implementation plan for admin/settings resolved runtime (#7803)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(admin): add redactor for resolved settings payload (#7803)
Pure helper that walks the live settings module and replaces known
sensitive paths (users.*.password, dbSettings.password,
sso.clients[*].client_secret, sessionKey, …) with [REDACTED] sentinel.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(admin): emit redacted runtime settings on /settings socket load (#7803)
Existing 'results' raw-file blob is unchanged so the textarea editor
and saveSettings round-trip continue to preserve \${VAR:default}
literals on disk. New 'resolved' field carries the in-memory settings
module run through the redactor — admin SPA can use it to show actual
runtime values next to env-var placeholders.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(admin): show resolved runtime value on EnvPill (#7803)
Admin SPA now stores the resolved field from the /settings socket
payload and exposes useResolvedAt(path) to walk it. EnvPill renders a
"→ active value" chip when the path is resolved, or "→ ••••••" with a
redacted tooltip when the server returned the [REDACTED] sentinel.
Old-server fallback (undefined resolved) keeps current behaviour.
The admin test script glob now picks up .test.tsx alongside .test.ts
so the new EnvPill tests run under tsx --test.
Closes#7803.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* admin: parsed JSONC settings editor with form view (#7603, #7666)
Takes over #7666 / closes#7603. Squashed rebase of 32 commits onto
current develop (which has since absorbed admin design rework #7716
and admin i18n fixes#7736 — granular history preserved on
takeover/7666-admin-settings-editor before this squash, see PR
description for the original commit log).
Highlights:
- New parsed JSONC settings editor under
admin/src/components/settings/ — FormView, ModeToggle,
ParseErrorBanner, JsoncNode dispatcher, leaf widgets (string,
number, bool, null, env pill), and pure helpers (comments,
envPill, jsoncEdit, labels, templateComments).
- ${VAR:default} env placeholders render as editable inline inputs
that round-trip through the raw textarea (env-pill spec asserts
this; docker-template spec protects against form-view degradation
on env-heavy configs).
- Schema-driven help text sourced from settings.json.template,
inlined at build time via vite (drops the runtime fs.allow
widening that earlier iterations needed).
- ModeToggle switches between FormView and raw textarea on
/admin/settings; parse errors surface in a non-blocking banner.
- jsonc-parser dep added; pure helpers wrap modify() for stable
edits that preserve key order and trailing comments (stops at
end-of-line so trailing-comment trains don't bleed into the next
property).
- i18n keys added for form mode, parse error, env pill,
default_label, and input aria.
- Playwright specs cover form view, env pill, parse error banner,
raw round-trip, and form-mode regressions called out in #7666
review (stable React keys from AST offsets, save-toast on server
ack only, NumberInput draft sync, parse-error flash during
initial load, .settings CSS conflict resolution, focus retention
via rAF, IconButton type defaulting to 'button').
Co-authored-by: Ayushi Gupta <ayushigupta36881@gmail.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(admin): stabilise React keys to prevent focus loss in settings editor
Switch React keys in JsoncNode and FormView from byte offsets to stable
JSON paths (`getNodePath(...).join('.')`). Byte offsets shift on every
keystroke because the edit changes the surrounding character count,
which forces React to remount inputs and lose focus mid-typing.
- Object children key on the property path.
- Array elements key on their JSON path index.
- Add a Playwright regression test pinning focus stability for array
element edits.
Co-authored-by: John McLear <john@mclear.co.uk>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(admin): stop trailing /* */ comments from bleeding into next key's label (#7740)
In the parsed settings form view, each key's row was rendering its label
as the previous keys' source lines concatenated together. Root cause:
findLeading() in admin/src/components/settings/comments.ts treated any
line ending in `*/` as a comment continuation, so a JSON line like
"altF9": true, /* focus on the File Menu and/or editbar */
was absorbed into the next sibling's leading comment block, and then
each subsequent key picked up an even longer accumulation.
- Tighten findLeading's isComment check to only match structural comment
lines (`//`, `/*`, or a `*`-prefixed continuation/close), so JSON code
with a trailing block comment no longer matches.
- Surface leading and trailing comments separately from the template
map. Leaf rows with only a trailing same-line comment now render the
humanized key as the row label and the comment as the help text below
the control, matching settings.json.template's convention (and #7740's
recommendation that "helper text should be below").
- Add unit tests pinning the regression and the JSDoc/`//` leading
styles, plus a Playwright spec that asserts altC's row carries a
clean label and the "focus on the Chat window" help text.
Closes#7740.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Ayushi Gupta <ayushigupta36881@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>