Commit graph

33 commits

Author SHA1 Message Date
John McLear
ea3032c079
i18n + a11y for admin disables warning (review feedback) (#7652)
Replace the hardcoded "Disables:" label and the inline title attribute
with proper i18n keys (admin_plugins.disables.label,
admin_plugins.disables.warning_title) and add role="alert" so screen
readers announce the warning instead of treating it as visual noise.

Per user review on #7649: "we should display it as a warning only if
a plugin disables a test... Also i18n!!! Always remember to do i18n."

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 19:25:21 +08:00
John McLear
e028016296
feat(admin): surface ep.json disables in /admin plugin browser (#7649)
Companion to ether/ether.github.com#395 — the admin UI's "available
plugins" listing now also renders the plugin's declared `disables`
(see doc/PLUGIN_FEATURE_DISABLES.md) so an operator about to click
Install sees the same warning as a user browsing etherpad.org/plugins:
"Disables: chat".

- src/node/types/PackageInfo.ts: optional `disables?: string[]` on
  the registry payload type.
- admin/src/pages/Plugin.ts: same on the admin-side PluginDef.
- admin/src/pages/HomePage.tsx: render an amber callout under the
  description when `disables` is present and non-empty. Plugins
  without a disables field render unchanged.

The plugin-registry build pipeline still has to start surfacing
`disables` from ep.json into plugins.json/plugins.viewer.json — until
that lands, the new callout no-ops everywhere, which is fine.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 10:29:25 +01:00
John McLear
e39dbde887
feat(updater): tier 1 — notify admin and pad users of available updates (#7601)
* docs(updater): add four-tier auto-update design spec

Four-tier opt-in self-update subsystem (off / notify / manual / auto / autonomous).
GitHub Releases as source of truth; install-method auto-detection with admin
override; in-process execution with supervisor restart; 60s drain + announce;
auto-rollback on health-check failure with crash-loop guard. Pad-side severe/
vulnerable badge that does not leak the running version. Top-level adminEmail
with escalating cadence (weekly while vulnerable, monthly while severe).

Refs: docs/superpowers/specs/2026-04-25-auto-update-design.md

* docs(updater): add PR 1 (Tier 1 notify) implementation plan

Bite-sized TDD task breakdown for shipping Tier 1 notify only:
- VersionChecker, InstallMethodDetector, UpdatePolicy, Notifier, state modules
- /admin/update/status (admin-auth) and /api/version-status (public, no version leak)
- Admin UI banner + read-only update page + nav link
- Pad-side severe/vulnerable footer badge
- Settings: updates.* block + top-level adminEmail
- Tests: vitest unit + mocha integration + Playwright admin/pad
- CHANGELOG + doc/admin/updates.md

PRs 2-4 (manual/auto/autonomous) get their own plans after PR 1 lands.

* feat(updater): add shared types for auto-update subsystem

* feat(updater): clarify OutdatedLevel and EMPTY_STATE doc, drop path header

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(updater): add semver helpers and vulnerable-below parser

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(updater): tighten semver regex to reject four-part versions

* feat(updater): add state persistence with schema validation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(updater): reject null email and array latest in state validation

typeof null === 'object' meant {email:null} passed the old isValid check,
which would crash downstream Notifier code reading email.severeAt. Likewise,
an array would pass the typeof latest === 'object' branch. Introduce
isPlainObject helper (null-safe, Array.isArray guard) and use it for both
fields. Adds two regression tests covering the exact broken inputs.

* feat(updater): add install-method detector with override

* feat(updater): add policy evaluator

* feat(updater): add GitHub Releases checker with ETag support

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(updater): validate release fields and preserve ETag on prerelease

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(updater): add email cadence decider

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(updater): tagChanged email fires regardless of cadence; drop unused field

* feat(settings): add updates.* and adminEmail settings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(updater): wire boot hook and periodic checker

Register expressCreateServer/shutdown hooks in ep.json and implement
the boot-wiring module that detects install method, starts the polling
interval and runs the notifier dedupe pass each tick.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(updater): add /admin/update/status and /api/version-status endpoints

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* i18n(updater): add english strings for update banner, page, and pad badge

* feat(updater): add pad footer badge for severe/vulnerable status

* feat(admin-ui): add update banner, page, and nav link

Add UpdateStatusPayload to the zustand store, a persistent UpdateBanner
rendered in the App layout, a /update page showing version details and
changelog, and a Bell nav link — all wired to the /admin/update/status
endpoint added in Task 10.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(updater): add Playwright specs for admin banner/page and pad badge

* docs(updater): document tier 1 settings, badge, email cadence

* refactor(updater): dedupe helpers, fix misleading log, add banner styling

- Export stateFilePath from index.ts and import it in updateStatus.ts (removes local duplicate)
- Import getEpVersion from Settings.ts in both index.ts and updateStatus.ts (removes two local definitions)
- Fix misleading 'backing off' log message — no backoff is implemented, just retries at next interval
- Remove EMPTY_STATE_FOR_TESTS re-export from state.ts; state.test.ts now imports EMPTY_STATE directly from types.ts
- Add .update-banner and .update-page CSS rules to admin/src/index.css

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(updater): address review feedback — async wrap, tier=off skip, poll race, opt-in admin gate

- Wrap /api/version-status and /admin/update/status with a small async helper
  so a rejected promise becomes next(err) instead of an unhandled rejection.
- Short-circuit route registration when updates.tier === 'off' so the heavier
  opt-out also removes the HTTP surface (matches pre-PR behavior for that case).
- Add an in-flight guard around performCheck() so overlapping interval ticks
  can't race on update-state.json writes or duplicate email decisions; track
  the initial setTimeout handle and clear it in shutdown().
- Add updates.requireAdminForStatus (default false) so admins can lock
  /admin/update/status to authenticated admin sessions without disabling the
  updater. Default false preserves current behavior (the running version is
  already exposed publicly via /health). Backend specs cover unauth → 401,
  non-admin → 403, admin → 200.
- Bump admin troubleshooting menu count test 5 → 6 to account for the new
  Update nav link.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(updater): address Qodo round-2 review feedback

Round 2 of Qodo review on #7601. Addressing the action-required items:

#1 Badge bypassed pad baseURL — derive basePath the same way
   padBootstrap.js does (`new URL('..', window.location.href).pathname`)
   and prefix the fetch with it. Subpath deployments now reach
   /<prefix>/api/version-status instead of 404ing.

#2 Updater poller could get stuck — `getCurrentState()` is now inside
   the try/finally so a one-time loadState() rejection can't leave
   `checkInFlight=true` and permanently silence polling.

#3 Updates off hung admin page — UpdatePage now self-fetches and
   renders explicit `disabled` (404), `unauthorized` (401/403), and
   `error` states instead of staying on "Loading...". Banner-driven
   prefetch is still honoured if it landed first.

#11 NaN polling interval — coerce `checkIntervalHours` to a number,
   clamp to [1h, 168h], log a warning and fall back to 6h on
   non-finite input. Math.max(1, NaN) === NaN previously meant a
   malformed settings.json could turn the poller into a tight loop.

#13 State validation accepted broken subfields — `isValid()` now
   inspects `latest.{version,tag,body,publishedAt,htmlUrl,prerelease}`,
   `vulnerableBelow[].{announcedBy,threshold}`, and
   `email.{severeAt,vulnerableAt,vulnerableNewReleaseTag}`. A
   hand-edited file with a number where a string is expected is now
   treated as corrupt and reset to EMPTY_STATE rather than crashing
   later in semver parsing or email rendering.

#14 Badge cache stampede — wrap `computeOutdated()` in a single-flight
   promise so concurrent requests at cache expiry await one shared
   computation instead of fanning out into N redundant disk reads.

Plus six new state.test.ts cases covering each new validation guard.

Pushing back on the remaining items:

#4 `updates.tier` defaults to `notify` — intentional. The whole point
   of tier 1 is to surface the "you are behind" signal to admins by
   default. Opt-in defeats the purpose; the existing failure mode
   (admin never hears about a security-relevant release) is exactly
   what this PR is fixing.

#5/#8 Admin status endpoint admin-auth — `currentVersion` is already
   public via `/health`, so wrapping the route in admin-auth doesn't
   reduce the disclosure surface meaningfully. Operators who want it
   gated set `updates.requireAdminForStatus=true` (already wired and
   covered by the comment on the route handler).

#10 Plain `https://` URLs in planning doc — planning markdown is
   viewed in editors and on GitHub where protocol-relative URLs would
   either render literally or break entirely. Keeping `https://`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 20:02:12 +08:00
John McLear
5fd600d608
fix(admin): restore i18n on /admin (issue #7586) (#7602)
* fix(admin): restore i18n on /admin by copying locales to the right path

The admin SPA fetches `/admin/locales/<lang>.json`. Building with
vite-plugin-static-copy and `src: '../src/locales'` was placing the
115 core locale files at `src/templates/admin/src/locales/` (the
plugin's `dirClean` strips a leading `../` but keeps the remaining
parent path). The express admin handler 404'd those fetches, fell
back to serving `index.html`, JSON.parse silently failed, and every
`<Trans>` rendered its raw key — see #7586.

Replace the plugin with a small inline build/dev plugin: at build
time copy `src/locales/*.json` to `<outDir>/locales/`; in dev serve
the same files via middleware so `vite dev` also works. Drop the
now-unused `vite-plugin-static-copy` dependency.

Add regression coverage that none of the existing admin specs had:
- backend HTTP test for GET /admin/locales/{en,de}.json
- Playwright admin i18n spec asserting translated <h1> renders for
  the default locale and for ?lng=de, plus a request-level check
  that the response is JSON, not the SPA fallback.

Closes #7586

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(admin): bundle locales via import.meta.glob, drop copy plugin

The first pass at #7586 replaced vite-plugin-static-copy with a
custom build/dev plugin that copied src/locales/*.json into the
admin output and served them in dev. That works, but the
vite-plugin-static-copy README explicitly recommends the public
directory or a JS import for this case, and the import path is
strictly cleaner: no copy step, no /admin/locales/* express route,
no SPA-fallback-shaped failure mode.

Use import.meta.glob in admin/src/localization/i18n.ts so each
language ships as its own hashed JSON chunk and is lazy-loaded on
demand. The vite config goes back to just react + base + outDir.
The plugin namespaces (e.g. ep_admin_pads) keep their existing
admin/public/<ns>/<lang>.json layout.

Tests:
- Drop tests/backend/specs/adminLocales.ts — it asserted on a
  /admin/locales/<lang>.json route that this approach no longer
  uses; the regression mechanism it pinned doesn't exist anymore
  and the test required the admin frontend to be built before the
  backend test runs (which CI doesn't do).
- Keep tests/frontend-new/admin-spec/admini18n.spec.ts (rendered
  <h1> in default and ?lng=de). Verified red→green: reverting just
  the loader to the pre-fix /admin/locales fetch makes both specs
  fail; restoring makes them pass.

Also update pnpm-lock.yaml to drop the now-unused
vite-plugin-static-copy entries — fixes ERR_PNPM_OUTDATED_LOCKFILE
that was failing every CI install upfront.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 03:07:45 +01:00
John McLear
36d61b2e29
fix: locale issues — custom strings caching, lang race, and window._() (#7454)
* fix: customLocaleStrings not applied due to aggressive locale caching

The admin panel's i18next backend used fetch with cache: "force-cache",
causing the browser to serve stale locale JSON even after the server
restarted with new customLocaleStrings in settings.json. The server
already sets appropriate Cache-Control headers (max-age based on
settings.maxAge), so the client-side force-cache was redundant and
prevented custom strings from appearing.

Fixes #6390

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: URL lang param now reliably overrides server default language

getParams() was processing server options first and URL params second,
both calling html10n.localize() for the lang setting. Since localize()
is async, the two calls raced and the result was nondeterministic.

Now processes each setting once: URL param wins if present, otherwise
falls back to server option. This eliminates the race condition.

Fixes #5510

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: window._() localization function always available for plugins

The html10n gettext shortcut window._ was only set if window._ was
undefined, but underscore.js was already setting it via the esbuild
bundle. Since internal code uses underscore via require() not window._,
it's safe to always set window._ to html10n.get so plugins can use
window._() for localization in hooks like documentReady.

Fixes #6627

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 01:58:33 +01:00
John McLear
09d782f695
Enforce 2-space indentation across codebase (#7426)
* Enforce 2-space indentation across codebase

Convert all 4-space indented source files to 2-space to match
.editorconfig and project contributor guidelines.

74 files converted: admin UI components, type definitions, security
modules, test files, helpers, and utilities.

No functional changes — 2882 insertions, 2882 deletions (pure
whitespace).

Fixes #7353

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Limit admin tests to chromium and firefox

Webkit is already tested in the dedicated frontend-tests workflow.
Running it again in admin tests causes flaky failures due to slow
socket connections and external API timeouts on webkit CI runners.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:48:45 +01:00
Edge-Seven
658ae78922
Fix typos in some files (#7227)
Co-authored-by: khanhkhanhlele <namkhanh20xx@gmail.com>
2025-11-18 10:33:10 +01:00
SamTV12345
fbf8ddeaa8
chore: added react compiler and fixed url to manage pads (#7158) 2025-10-06 12:41:26 +02:00
SamTV12345
f0e7942a55
chore: use only rolldown for building (#7101) 2025-08-26 22:22:10 +02:00
SamTV12345
a5413d7272
chore: added possibility to create pads via admin menu (#7100) 2025-08-26 21:51:13 +02:00
SamTV12345
40884fa96b feat: disable stats endpoint if enableMetrics is false 2025-07-27 22:22:18 +02:00
SamTV12345
840fc982c4 Fixed comp problems 2024-12-22 16:54:56 +01:00
SamTV12345
0b26405201
fix(admin): Fixed updating plugins (#6705) 2024-10-10 18:15:48 +02:00
Stefan Müller
1ad9418a6f
Add code for revision cleanup (#6442)
* Add initial code for revision cleanup

* Some improvements - code cleanup

* Cleanup logging

* Add button in admin backend to cleanup revisions of a specific pad

* Disable cleanup by default and show errors in admin area

* Improve cleanup code

* Load revisions for cleanup in parallel

* Consider saved revisions during pad cleanup
2024-09-14 15:54:30 +02:00
SamTv12345
08f199178d Fixed admin panel 2024-09-13 15:44:19 +02:00
SamTv12345
178fe7c24d Fixed admin panel mobile view. 2024-09-13 15:36:39 +02:00
SamTV12345
221f6f2002
Added sorting for plugins (#6580) 2024-08-13 21:32:40 +02:00
SamTV12345
f7b1311e36 Fixed sorting of other pad columns 2024-08-06 20:43:10 +02:00
samyakj023
161dd72690
next-page-disabled-if-zero-page (#6457) 2024-06-18 19:28:03 +02:00
Helder Sepulveda
a637921160
Move away from using toast in the plugin search (#6441) 2024-06-10 19:00:58 +02:00
Helder Sepulveda
13e160cbe4
Clean comments (#6420)
* Add script to trigger test on utils

* Add new function to remove the comments from the settings file.
It reduces the size of the payload when we save on the admin page `.../admin/settings`

* Add     font-family: monospace; to the settings
2024-06-04 19:32:21 +02:00
SamTV12345
df3686dcad
Fixed pagination of pads (#6406) 2024-05-24 22:32:03 +02:00
SamTV12345
e12be96102
feat(admin): Added shoutout to admin panel (#6346)
* Added shoutout

* Added shoutout function

* Fixed test.

* Included feedback from review.

* Removed unnecessary file
2024-04-21 17:58:51 +02:00
SamTV12345
9d8f1f60cc
Fixed some minor admin bugs (#6335) 2024-04-16 19:48:34 +02:00
SamTV12345
a541375f7f Fixed plugin updates 2024-04-16 19:16:38 +02:00
SamTV12345
0b80e256b4
Added proxy support for axios. (#6334) 2024-04-16 19:11:05 +02:00
kekePower
39ef8f1504
LoginScreen.tsx -> Passwort -> Password (#6299)
Found a typo in LoginScreen where is says Passwort instead of Password.
2024-04-02 18:59:37 +02:00
SamTV12345
0e4937b50f Improved login admin page. 2024-03-14 22:36:53 +01:00
SamTV12345
cda40c91c2 Added eye icon. 2024-03-14 16:43:14 +01:00
SamTV12345
9575ab8457 Added better looking pad scroll. 2024-03-14 16:43:14 +01:00
SamTV12345
73dff0bfe7
Begin redesigning admin panel. (#6219)
* Begin redesigning admin panel.

* Added monaco editor.

* Fixed tests
2024-03-13 15:47:02 +01:00
SamTV12345
c2699e4528
Added playwright tests. (#6212)
* Added playwright tests.

* Added clear authorship color.

* Ported enter ts.

* Ported more tests.

* Commented helper tests.

* Fixed admin tests.

* Fixed.

* Fixed admin pages not there.

* Fixed waiting.

* Upload playwright report.

* Remove saucelabs

* Fixed waiting.

* Fixed upload artifact.

* Also install deps.

* Added retry mechanism.

* Added timeout for restart etherpad server.

* Fixed tests.

* Added frontend playwright tests.
2024-03-10 23:18:50 +01:00
SamTV12345
db46ffb63b
Feat/admin react (#6211)
* Added vite react admin ui.

* Added react i18next.

* Added pads manager.

* Fixed docker build.

* Fixed windows build.

* Fixed installOnWindows script.

* Install only if path exists.
2024-03-09 23:07:09 +01:00