-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Comparing changes
Open a pull request
base repository: ether/etherpad
base: master
head repository: ether/etherpad
compare: develop
- 8 commits
- 23 files changed
- 4 contributors
Commits on May 6, 2026
-
Merge branch 'master' into develop
Etherpad Release Bot committedMay 6, 2026 Configuration menu - View commit details
-
Copy full SHA for 45b000d - Browse repository at this point
Copy the full SHA 45b000dView commit details
Commits on May 7, 2026
-
fix(7686): username 'false' / 'malformed color: false' for legacy set…
…tings.json (#7688) * fix(7686): legacy padOptions.userName/userColor=false breaks pad Settings.json files generated before December 2021 used `false` as the default for these two string options (commit 8c857a8 switched the template default to `null` and noted "this change has no effect due to a bug in how pad options are processed; that bug will be fixed in a future commit" — the follow-up never landed). pad.ts:getParams() then runs `false.toString()`, the resulting string "false" passes the `!== false` sentinel check at _afterHandshake, and notifyChangeName ships USERINFO_UPDATE with name="false" and colorId="false" (clobbered via clientVars.userColor). The server's hex regex rejects the colour and throws `malformed color: false`; the user sees their name as "false" and a white swatch. Defense in depth: - Server: Settings.ts::reloadSettings() coerces legacy boolean false to null for padOptions.userName / padOptions.userColor and warns the operator, matching the existing disableIPlogging shim pattern. - Client: the pad.ts userName / userColor callbacks reject the literal "false" string so URL params (?userName=false) and any other path that surfaces the sentinel as a string are also no-ops. - Backend regression test mirrors the shim and asserts it normalizes legacy false, leaves explicit values intact, leaves null untouched, does not coerce other padOptions keys, and does not coerce the string "false" (that path is the client guard's responsibility). Closes #7686 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(7686): guard padOptions shim against non-object config (Qodo) Qodo flagged that storeSettings() will overwrite settings.padOptions raw with whatever settings.json supplies — including null, primitives, or arrays — which would make the new userName/userColor shim crash on property access. Add a shape guard so the shim is a no-op for malformed padOptions, and extend the regression test to cover null / primitive / array shapes. This doesn't change which configs work (Pad.ts also assumes padOptions is an object and would already crash on a null padOptions when a pad is opened) but it stops the shim from being the loud thing in the stack trace if someone hits it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for da87a4f - Browse repository at this point
Copy the full SHA da87a4fView commit details -
feat(settings): enable Pad-wide Settings by default; fix misleading m…
…odal title (#7679) * feat(settings): enable Pad-wide Settings by default; fix misleading modal title The creator-owned Pad-wide Settings feature (#7545) shipped behind a flag that defaulted to false. With the flag off the modal still rendered an H1 of `pad.settings.padSettings` ("Pad-wide Settings") for *every* user, even though no pad-wide controls were ever shown. Two readers in different browsers both saw "Pad-wide Settings" as the modal title, which looked like a creator-gate regression but was just a copy bug. Two changes: 1. Flip the default of `enablePadWideSettings` to `true` (Settings.ts plus both settings templates). With the feature on, the creator (revision-0 author) gets a real "Pad-wide Settings" section gated by `clientVars.canEditPadSettings`, while every other user sees only "User Settings" — matching the design intent of #7545. This is a behavior change, so the settings comments are expanded to describe what the toggle now does. 2. Drop the conditional H1 in `src/templates/pad.html` and always use `pad.settings.title` ("Settings"). Operators who explicitly disable the feature shouldn't see a label that lies about a section that isn't rendered. Adds backend regression coverage in `tests/backend/specs/socketio.ts`: - Different browsers (different cookie jars => different authorIDs): only the first joiner gets `canEditPadSettings: true`. - Same browser, two tabs (shared HttpOnly token cookie => same authorID): both connections are the same identity, both correctly land on the creator path. * test(settings): regression coverage for the settings modal H1 Asserts the rendered `/p/<id>` HTML always uses `data-l10n-id="pad.settings.title"` for the modal heading, regardless of `enablePadWideSettings`. Catches a re-introduction of the old conditional that printed "Pad-wide Settings" for every user when the feature was off. Action of Qodo review feedback on PR #7679.
Configuration menu - View commit details
-
Copy full SHA for b751fd7 - Browse repository at this point
Copy the full SHA b751fd7View commit details -
fix(docker): share corepack cache so etherpad user can resolve pnpm (#…
…7689) * fix(docker): share corepack cache so etherpad user can resolve pnpm (#7687) PR #7674 switched the Dockerfile from `npm install -g pnpm` to corepack and `corepack prepare pnpm@${PnpmVersion} --activate`. The activate step runs as root and writes its lastKnownGood pin into `$COREPACK_HOME`, which defaults to `~/.cache/node/corepack` — i.e. a per-user path. The Dockerfile then drops to `USER etherpad` and later runs `bin/installLocalPlugins.sh`, which invokes `pnpm` as etherpad. With an empty per-user corepack cache and no shared activation file, corepack re-resolves pnpm and (for forks/configs without a `packageManager` pin matching the activated version) can fall back to "latest" from the registry — pulling `pnpm@10.33.4` instead of the requested 11.x and failing the workspace's `engines.pnpm` check. Pin `COREPACK_HOME=/opt/corepack` and chown it to etherpad after the prepare step. Both root and etherpad now share the same lastKnownGood file and tarball cache, so etherpad inherits the activated pnpm without hitting the registry again. Verified end-to-end: - `docker build --target development --build-arg ETHERPAD_LOCAL_PLUGINS=ep_test` with a stub local plugin runs `installLocalPlugins.sh` cleanly: `Done in 16.6s using pnpm v11.0.6`. - `docker run ... pnpm --version` as etherpad reports 11.0.6 from the shared cache — no "Unsupported environment" error. Note: corepack still emits a one-time "about to download" line at runtime because `corepack prepare pnpm@11.0.6` resolves to the highest matching patch (11.0.8) at build time while the project's `packageManager` field pins exactly 11.0.6. That's a follow-up — the download succeeds non-interactively and the engine check passes. Fixes #7687. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(docker): action Qodo PR review (#7687 follow-up) - Replace hard-coded /opt/corepack with ${COREPACK_HOME} in mkdir/chown so the env var stays the single source of truth (Qodo: "COREPACK_HOME path duplication"). - Add a build-test-local-plugin job to .github/workflows/docker.yml that builds the development target with a stub ETHERPAD_LOCAL_PLUGINS so the original failure mode (corepack/pnpm cache invisible across the USER switch) cannot silently regress (Qodo: "COREPACK_HOME fix lacks test"). The job is small — `docker build` only, no run — and uses the shared GHA buildx cache. Verified: same docker build + `docker run pnpm --version` flow on the variable form gives identical output (pnpm 11.0.6 from the etherpad-owned cache). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for fe9727b - Browse repository at this point
Copy the full SHA fe9727bView commit details -
fix(7606): sync theme-color meta with client-side dark-mode switch (#…
…7690) * fix(7606): sync theme-color meta with client-side dark-mode switch PR #7636 emits <meta name="theme-color"> server-side from settings.skinVariants. That covers operators who hard-code a dark toolbar in settings.json, but not the runtime path: pad.ts auto-flips the toolbar to super-dark when enableDarkMode is on, the browser reports prefers-color-scheme: dark, and no localStorage white-mode override is set, plus the user can flip it via #options-darkmode. Both paths run skinVariants.updateSkinVariantsClasses(), which until now never touched the meta — so dark-mode users kept the light #ffffff baseline and saw a white address bar above a dark toolbar (stffen on #7606 after 2.7.3). Push the toolbar-color lookup into updateSkinVariantsClasses so the meta tracks every class change: the auto-switch on init, the user toggle, and the skinVariants builder. Mirrors the CSS-source-order table from src/node/utils/SkinColors.ts (last matching *-toolbar token wins). When no meta is present (non-colibris skin, server omits it) the helper is a no-op. Adds Playwright coverage for both paths under colorScheme: 'light' (manual toggle) and 'dark' (auto-switch on dark-OS clients — the case stffen reported). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(theme-color): action Qodo PR review (1) Bug — duplicated toolbar→color table: extract the CSS-source-order mapping and the default-color constant into src/static/js/skin_toolbar_colors, re-imported by both src/node/utils/SkinColors.ts (server, EJS template helper) and src/static/js/skin_variants.ts (client, runtime updates). Lives under static/js so the browser bundle can resolve it; server-side imports of static/js modules already exist (Changeset, AttributeMap, ImportHtml, hooks). One source of truth means a future palette change can no longer silently desync the server-rendered baseline meta from the client updates, which was the exact regression that brought us here. (2) Rule violation — 4-space continuation indentation in the new Playwright spec: re-indent the themeColor helper and the multiline test(...) call to the repo's 2-space rule (.editorconfig). Existing backend coverage (configuredToolbarColor unit tests + the specialpages server-render checks for both pad and timeslider) still passes against the refactored helper, so it's regression-locked end to end. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for ab0cff4 - Browse repository at this point
Copy the full SHA ab0cff4View commit details -
feat(socialMeta): settings.socialMeta.description override (#7599 fol…
…low-up) (#7691) Issue #7599 follow-up from @stffen: the OG description has no obvious settings.json knob and the i18n catalog default is English, but most preview crawlers (WhatsApp, Signal, Slack, Telegram, Facebook) don't send Accept-Language and so always hit the English fallback regardless of how many locale files translate `pad.social.description`. Keep the i18n catalog as the default source — translatable strings belong in locale files, per the original Qodo review on PR #7635 — but add an explicit `socialMeta.description` setting that wins when set as a non-empty string, regardless of negotiated language. This is the lever that fixes the crawler case for non-English instances without re-introducing per-language config in settings.json (operators who want that still use customLocaleStrings). - Empty/whitespace overrides are treated as unset (would otherwise silently blank the preview). - Override is HTML-escaped via the same path as every other value. - og:locale stays language-negotiated; only the description is forced. - Documented next to publicURL in settings.json.template and settings.json.docker (env var SOCIAL_META_DESCRIPTION). The customLocaleStrings example now spells out pad.social.description so operators discover both routes. 5 new unit specs + 4 new integration specs cover override-wins, null/missing fallback, blank-treated-as-unset, and HTML-escaping. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 90aafb1 - Browse repository at this point
Copy the full SHA 90aafb1View commit details -
fix(socialMeta): coerced numeric/boolean override silently dropped (#…
…7692) * fix(socialMeta): coerced numeric/boolean override silently dropped Qodo flagged on PR #7691: Settings.coerceValue() turns numeric-looking env vars into numbers and "true"/"false" into booleans, so e.g. SOCIAL_META_DESCRIPTION="2026" arrives at the resolver as the number 2026. The previous resolver gated on `typeof override === 'string'`, so it silently fell back to the i18n catalog with no warning — the operator's docker config would appear broken. Accept string|number|boolean and stringify before the empty-check; null / undefined / unsupported types still fall through to the catalog. Two new unit specs cover the numeric and boolean coercion paths. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(socialMeta): widen description type to match coerced runtime Action Qodo bug-find: SettingsType.socialMeta.description and SocialMetaSettings.description still claimed `string | null`, but Settings.coerceValue() can produce number|boolean from env-var-driven config — the previous resolver fix was correct at runtime but the type mismatch forced `as unknown as string` casts in the new tests. Widen both declared types to `string | number | boolean | null` to match runtime reality, drop the typeof string|number|boolean guards in the resolver (the union now narrows automatically) and remove the test casts. Behaviour is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for a356414 - Browse repository at this point
Copy the full SHA a356414View commit details -
Configuration menu - View commit details
-
Copy full SHA for bcf5c91 - Browse repository at this point
Copy the full SHA bcf5c91View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff master...develop