- use OAuth instead of tokens
- add an integration card
- improve error handling
- add BibLaTeX format support
- fix indexing of linked .bib files on creation
Make Template Gallery optional; rename environment variables
Refactor Template Gallery; resolves#38 and #39:
- replace free-text license input with a select box
- improve visual presentation of modals and enhance keyboard interaction
Template Gallery: replace markdown-it with marked
Fix template publishing to align with upstream project context changes
Template gallery: ui components were moved to shared folder
Fix style of Templates button in navbar
Template gallery: Fix `OLModal` usage (see upstream commit 19b3834)
Template gallery: Fix import after upstream converted `CompileManager`, `ClsiManager` and `RateLimiterMiddleware` to ESM
Template gallery: Fix import after upstream converted `AuthenticationController`, `ProjectGetter`, ProjectLocator` and `DocumentUpdaterHandler` to ESM
Template Gallery: migration to 6.1.0
- enable menu for editor redisign
- move frontend code to modules
Template gallery: add template management authorization middleware
- middleware to enforce template access rules
- introduce template manager role
- fix minor issues
Template Gallery: fix for 6.2.0
Template Gallery: fix for 6.3.0 and show language in the details
* Rename user-facing Papers reference manager text to ReadCube
* Rename Papers component and files name to Readcube
* Update locales from Papers to ReadCube
* Rename ID name from papers to readcube
* Fix a chinese locale to use ReadCube
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
GitOrigin-RevId: ee89e3f5da5bcf9987c0ee3e558b9ae1dab9372c
* Remove `plans2026` from pug files in subscriptions module
* Remove `plans2026` param from `makeGroupPlans`
* Remove `plans2026` param from `makeUISettings` in interstitial-payment.mjs
* Remove `plans2026` param from `makeInterstitialPaymentConfig` in interstitial-payment.mjs
* Remove `plans2026` param from `makeIndividualPlans`
* Remove `plans2026` param from `makeStudentPlans`
* Remove `plans2026` from try-premium page
* Remove `plans2026` from controllers
* Remove unused files
* Update translations
* Update tests
* Update tests
* Remove unused translations
* Rename the collaborator upgrade-mode test to read explicitly as the
Standard-plan replacement for the removed redirect test, and drop the
stale "when plans 2026 is enabled" framing now the controller no longer
branches on the flag.
* Surface controller errors in InterstitialPayment tests
Move assertions out of the res.render callback into render/redirect
helpers that resolve with the captured args and reject on the wrong
path or a controller rejection, so failures show the real error
instead of timing out. Restore the ai-limit-upgrade-copy split-test
assignment for the AI copy tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* format
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
GitOrigin-RevId: f0b055b4d92b494b531766a13b057336d9c2c9af
* Hide tax note when tax is included and update zero-tax disclaimer wording
* fix: update taxes_may_be_added key in all non-English locale files
GitOrigin-RevId: 9cd0e0aba6d548221e97d383b0a2e52a2e0a077c
* Remove double spaces
* Enforce curly apostrophes
* Enforce French typographic spaces in fr.json
Add vitest test enforcing French spacing rules per
https://typographisme.net/post/Les-espaces-typographiques-et-le-web:
- NNBSP (U+202F) before ? ! ;
- NBSP (U+00A0) before :
- NBSP (U+00A0) around guillemets « »
Fix 38 fr.json values that were using NBSP (or no space) before ? ! ;.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Extend French typography test to numbers and percent signs
Add rules per https://typographisme.net/post/Les-espaces-typographiques-et-le-web:
- NNBSP (U+202F) between digit groups (thousands separator)
- NBSP (U+00A0) between a number and a following word/unit
- NBSP (U+00A0) before %
Fix 9 fr.json values where a regular space was used instead of NBSP between
a number and a following word (e.g. "1 résultat", "10 jetons", "7 jours").
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Use point médian for inclusive writing in fr.json
Replace parenthetical gender/plural markers like "sûr(e)", "abonné(e)",
"licence(s)" with the point médian "·" (e.g. "sûr·e", "abonné·e",
"licence·s") per modern French écriture inclusive.
Add a vitest rule rejecting "word(suffix)" patterns where suffix is 1-3
letters and there is no space before the opening parenthesis.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Simplify inclusive-writing check to "(e)" substring match
The previous regex (matchAll without the /g flag) would have thrown at
runtime. Drop matchAll entirely and use includes('(e)').
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Add point médian to participles in fr.json
Apply inclusive writing (·e) to past participles agreeing with the
addressed user ("affilié·e", "invité·e", "connecté·e", "abonné·e", etc.).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Use inclusive forms in fr.json
* Change "de Overleaf" to "d’Overleaf"
* Fix tests
* Check for consecutive spaces, not just double spaces
* Update comment about guillemets
* Add ESLint rules for locale JSON conventions
Add three rules to @overleaf/eslint-plugin that run against locale JSON
files via @eslint/json:
- no-consecutive-spaces-in-locales
- no-straight-apostrophes-in-locales
- french-typography-in-locales
Wire them up in services/web/eslint.config.mjs against `locales/*.json`
(and `locales/fr.json` for the French-typography rule).
* Add `@eslint/json` so JSON files can be parsed
* Scope JS/TS-specific config to JS/TS files only so that built-in rules aren't applied to JSON files
* Disable `no-irregular-whitespace` in french-typography-in-locales.js
* Make the rules fixable
* Improve regexes: user `\s` instead of custom matchers
* Add sorted-keys-in-locales ESLint rule
Mirrors scripts/translations/sort.js as a fixable ESLint rule:
require top-level keys in locale JSON files to be sorted alphabetically.
The autofix re-serializes the file with sorted keys.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Add no-unused-locale-keys ESLint rule
Mirrors scripts/translations/cleanupUnusedLocales.js as a fixable ESLint
rule applied only to en.json. Shells out to `find` + `cat` once per
process (cached) to grep all candidate source files for key references,
then reports any en.json key that isn't found. The autofix re-serializes
en.json without the unused keys.
Hardcoded ALWAYS_USED set covers keys built at runtime (month names,
third-party-datastore notifications) that the regex scan can't see.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Add locale-variables-match-en ESLint rule
Mirrors scripts/translations/checkVariables.js as an ESLint rule applied
to non-en locale JSON files. Reads en.json (cached) and reports any
member whose `__name__` placeholders differ from the base.
GLOBALS (e.g. __appName__) are allowed as extras; IGNORE_NESTING_FOR
preserves the script's per-key exceptions.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Replace some double linebreak (@overleaf/no-consecutive-spaces-in-locales)
* Add no-orphan-locale-keys ESLint rule
Detect translation keys in non-en locale files that aren't present in
en.json. Mirrors the `--sync-non-en` flag of cleanupUnusedLocales.js.
The autofix re-serializes the locale file without the orphan keys,
sorted alphabetically.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Add tests for the locale JSON ESLint rules
Cover the four single-file rules:
- no-consecutive-spaces-in-locales
- no-straight-apostrophes-in-locales
- sorted-keys-in-locales
- french-typography-in-locales (including the inclusive-writing
suggestion for "(e)")
The three cross-file rules (no-unused-locale-keys, no-orphan-locale-keys,
locale-variables-match-en) read from disk and aren't covered here; they
need integration tests via fixtures.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Drop bin/lint_locales — checks are now covered by ESLint rules
The four checks in bin/lint_locales are duplicated by the new
@overleaf/eslint-plugin rules:
- sort.js --check → sorted-keys-in-locales
- cleanupUnusedLocales.js --check → no-unused-locale-keys
+ no-orphan-locale-keys
- checkVariables.js → locale-variables-match-en
- single-quote grep → no-straight-apostrophes-in-locales
`yarn lint` runs the ESLint rules against locales/*.json, so the
lint_locales script and Makefile target are redundant.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Remove Locales.test.mjs
* Delete scripts replaced by @overleaf/eslint-plugin rules
Remove the three locale scripts now superseded by ESLint rules:
- scripts/translations/sort.js → sorted-keys-in-locales
- scripts/translations/cleanupUnusedLocales.js → no-unused-locale-keys
+ no-orphan-locale-keys
- scripts/translations/checkVariables.js → locale-variables-match-en
Also drop the matching Makefile targets (sort_locales,
cleanup_unused_locales), update AGENTS.md / copilot-instructions.md to
point at `yarn lint --fix` instead, and prune the deleted entries from
the esm-check-migration allowlist.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Delete redundant scripts/translations/sort-locale-file.js
Single-file sort utility — superseded by `yarn lint --fix path/to/file.json`
via the sorted-keys-in-locales ESLint rule. No callers in repo.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Update comments and messages
* Add test file pattern to ESLint configuration
* Reorder "Backend specific rules" so `no-extraneous-dependencies` doesn't fail on test files
* Make french-typography fixes idempotent and catch edge cases
Apply Copilot's review feedback on PR #34221:
- autoFix() now uses `\\s*`/`\\s+` instead of `\\s?`/`\\s` so it
collapses any run of mixed whitespace into the correct NBSP/NNBSP,
making the fix idempotent and order-independent.
- The `:` lint regex now captures optional whitespace and reports
when it isn't NBSP (catches `"Liste :"` with a regular space).
- The `%` lint regex now matches the missing-space case (`"10%"`)
via `\\s*` instead of requiring one char between digit and `%`.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Remove sort-locale-file.js from pre-commit
* Revert no-unused-locale-keys ESLint rule; Restore lint_locales scripts
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
GitOrigin-RevId: 8351fab074e6e7f77920b70237df1cd1c781e053
* Replace token-link email with 6-digit code on SSO registration
Unverified SSO emails previously received a long-lived token link
(90-day TTL) via UserEmailsConfirmationHandler. This replaces that
flow with the same 6-digit code verification used for password
registration, redirecting through /registration/confirm-email.
- SSOManager.registerSSO now always confirms email (caller must
verify first); removes sendConfirmationEmail / _finishRegistration
- SSOController._signUp sends confirmation code and stores
pendingSSORegistration in session when IdP email_verified is false
- New SSOConfirmEmailHandler completes registration after code check
via completeSSOEmailConfirmation module hook
- OnboardingController confirm-email handlers accept
pendingSSORegistration alongside pendingUserRegistration
confirmEmailFromToken (POST /user/emails/confirm) removal is deferred
to a follow-up PR to avoid breaking in-flight 90-day tokens.
Closes#28607
* Fix unverified-email edge cases; Add ORCID e2e tests;
* Rename `confirmEmail` parameter to `emailVerifiedByIdP` in _signUp function
* Remove `sendConfirmationEmail`
* Mock getUserByAnyEmail in tests
* Extract _finishSSORegistration helper to deduplicate the register →
set session flags → allocate referral → finishSaasLogin → finishLogin
sequence shared by both the direct and deferred (code-confirmed) paths.
* Stop duplicating session data in pendingSSORegistration
analyticsId, splitTests, and referal_* are already in the session at
confirmation time — no need to copy them into pendingSSORegistration.
Re-fetch splitTests fresh on completion instead.
* Simplify the code
* Remove dead confirmEmail template
No callers remain after sendConfirmationEmail was deleted. The token-link
flow (confirmEmailFromToken) only validates tokens, never sends email.
* Remove dead reconfirmEmail template
* Address comments from Copilot
* Clear stale pending registration when starting a new flow
* Add unit tests for completeSSOEmailConfirmation
* Add `verificationMethod` param
* Fix camelcase issues
* Extract _createSSOUser and _registerAndFinish helpers to deduplicate registration logic
* Remove obscure "registration_error"
* Prevent FormTextIcon from shrinking
* Enable "email_already_registered_sso" error
* Misc. improvements to confirm-email-form.tsx
* Remove `UserEmailsConfirmationHandler` mock
Co-authored-by: Olzhas Askar <olzhas.askar@overleaf.com>
* Add info on sso_email.pug page
---------
Co-authored-by: Olzhas Askar <olzhas.askar@overleaf.com>
GitOrigin-RevId: d0196ebc6d81ff61bcd27726d0b899b743d08d64
* [web] Redirect missing AI add-on purchase to subscription dashboard
The two error paths in `previewAddonPurchase` redirected to
`/user/subscription/plans#ai-assist`, but the `#ai-assist` anchor was
removed when the AI Assist add-on was retired, so users land at the top
of the plans page with no context. Align both with the other error
branches in the same function and the `plans-2026-phase-1` enabled
branch, which already redirect to
`/user/subscription?redirect-reason=ai-assist-unavailable` — the
subscription dashboard shows the matching warning alert
(`redirect-alerts.tsx`).
Update the acceptance test to match the new redirect target.
Closes#34074
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [web] Update ai-assist-unavailable warning to reflect bundled AI features
The previous copy said "AI Assist isn't available to you due to your
current subscription type", which read as a hard block. Now that the AI
Assist add-on has been retired and AI features are included with every
paid plan, the warning should point users to the pricing page instead of
implying their plan can't access AI at all.
Keep the existing translation key for now — a follow-up can rename it
once #33624 (AI page CTA destination) is resolved.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [web] Link the ai-assist-unavailable warning to the pricing page
* [web] Rename key `ai_assist_unavailable_due_to_subscription_type` -> `ai_assist_unavailable`
* [web] Update french and german translations
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GitOrigin-RevId: ae1319fa5b857d8f292de77c82ef0bda1c7ad144
* Add tests on plurals
* Update `collabs_per_proj` and its pluralisations
* Update `n_user` and its pluralisations
* Update `showing_x_results` and its pluralisations
* Update `show_x_more_projects` and its pluralisations
* `bin/run web npm run extract-translations`
* Populate `_plural` keys in non-en locales
For 2-form languages (da, de, es, fi, fr, it, nl, no, pt, sv, tr), copy
the existing bare-key value into the new `_plural` sibling to prevent
i18next from falling back to English for count!=1.
Also remove orphan singular keys (`collabs_per_proj_single`,
`showing_1_result*`) left over from the previous commits.
Bare-key values remain in their original plural form pending translator
review — count=1 will still render the plural form in non-en until
translators flip those to singular. Multi-form (cs, pl, ru) and
single-form (ja, ko, zh-CN, zh-TW) locales are unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Flip non-en bare-key values to singular form
Per review, the i18next v3 plural convention uses the bare key for count=1
(singular) and `_plural` for count!=1. The non-en bare-key values were
left as the original plural form by the previous commit so the `_plural`
siblings could be copied from them; this commit flips the bare values to
the singular form per language.
Languages where singular and plural noun forms coincide (Finnish, Swedish,
Turkish) are unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Apply suggestions from code review
Co-authored-by: Olzhas Askar <olzhas.askar@gmail.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Olzhas Askar <olzhas.askar@gmail.com>
GitOrigin-RevId: 628513ca792c2dcce023247e52b7320e2741cc54
* [web] Replace `pro` with `commons` wording on institutional subscriptions
Replaces the wording in several places:
- subscription settings
- email tags
- features tooltip
- institution portal
GitOrigin-RevId: 1b9a0e51245ed8a41865300d9e9d555bc05e6c17
* Change the refund policy from 30 to 14 days
* Align AI suggestions trial period with 14-day refund policy
* Revert "Align AI suggestions trial period with 14-day refund policy"
This reverts commit d3327c71c05543a751acd66450183bbf0eb95fd7.
GitOrigin-RevId: b77e09b2bb508951b68ae3a00b95146e6898bac5
* adding plural translations for the languages that were easy to test with the help of AI
* adding remaining translations
* adding your_subscriptions
* running make sort_locales
* fixing nl.json to make it formal You
GitOrigin-RevId: 7510e2f8eee87fd2a256ece434cc59e6877893e6
* Conditionally render a CIAM copy of login.pug depending on `ciam` split-test
* Conditionally render a CIAM copy of register.pug depending on `ciam` split-test
* Conditionally render a CIAM copy of institutional_login.pug depending on `ciam` split-test
* Rename the test to `uniaccessphase1`
* Fixup ciam paths (underscores, not hyphens)
* Escape translations in `log_in_with_existing_institution_email`
See https://github.com/overleaf/internal/pull/29390#discussion_r2479318609
GitOrigin-RevId: fff0e154d1e1faad4842a2c49fa5889f9cc189e6
* Temporarily update `maxEntitiesPerProject` to test `FileTreeModalCreateFile`
* Remove unused CSS
* Move project_has_too_many_files Notification to the modal body
* Turn project_approaching_file_limit message into a Notification
* Update project_has_too_many_files translation with `fileCount.limit`
* Update other project_has_too_many_files with limit parameter
* Add translations for project_has_too_many_files_limit
* Revert "Temporarily update `maxEntitiesPerProject` to test `FileTreeModalCreateFile`"
This reverts commit 704996aa96c9ba592c7e44d165def0b97d30bed1.
* Fix unit tests
* Move the warning notification to the modal's body
---------
Co-authored-by: Rebeka <o.dekany@gmail.com>
GitOrigin-RevId: 0f54db7021e4cd4537a14e4f9e1d8ef54337778c