* add ELINT_FAST environment variable in pre-commit hook
skips slow type-aware linting in pre-commit hook, full lint still runs in CI
GitOrigin-RevId: d4b6fde1c5010ba0f61aed03972b745af0f55b9b
* [web] Fix Stripe Subscription ID being saved to wrong field in admin panel
* add migration for unsetting recurlySubscription_id
GitOrigin-RevId: ccae470897690a8cdc8a8bce883983808a963d24
* Basic focus mode implementation
* Exit button
* Toggle between editor pdf mode
* Keep the rail and file tree mounted for editor tabs to work properly
* Hide Switch to editor button in focus mode
* Show shortcuts in layout menu
* Gate the feature behind a focus-mode feature flag
* Add split test badges in the focus mode dropdown item and top bar
* Add analytics tracking for focusMode changes
* Cleanup leftover IdeView value
* Allow passing focusMode value in layout test provider
* Remove redundant listener for focus mode shortcut
* Update focus mode and full project search listeners to use the event key
* Post-rebase cleanup
---------
Co-authored-by: Anna Fields <acfields11@gmail.com>
GitOrigin-RevId: 207f8d136fa6662558c474cca4a867a9842191e7
* 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
* [monorepo] consolidate clsi-lb host/ip env-vars
Target env-var is CLSI_LB_HOST. Keep CLSI_LB_IP populated for a week.
* [clsi] initial version of /convert/pdf-to-jpeg
* [rails] use fake-secrets in CI and Codespaces
* [rails] adapt tests for using clsi to convert PDFs to image
* [rails] add rake task for comparing clsi conversion with transloadit
* [clsi] double check that output.jpg is a regular file
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
* [clsi] fix composing basename
* [monorepo] fix clsi-lb host env-var post merge
* [monorepo] sort dev-environment.env hosts
* [rails] use local pdf file rather than downloading it again
Download from the old renderer code path still. It's dead code.
* [terraform] clsi: enable pdf to jpg conversion
---------
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
GitOrigin-RevId: 5ecaa8559d299486340bb3961f06b29f7c4dfcca
* [web] Order plans in Change Plan modal consistently
Reorder the plans returned by `buildPlansListForSubscriptionDash` so the
Subscription page "Change plan" modal lists them top-to-bottom as:
1. Student annual
2. Student monthly
3. Standard monthly
4. Standard annual
5. Pro monthly
6. Pro annual
Previously `buildPlansList` produced three per-period buckets which the
dash function concatenated, giving an order that flipped per family.
Replace that with an explicit `CHANGE_PLAN_MODAL_PLAN_CODES` list so the
order matches the Design QA spec at a glance. The now-unused
`studentAccounts`, `individualMonthlyPlans`, `individualAnnualPlans`,
`groupMonthlyPlans`, and `groupAnnualPlans` buckets are dropped from
`buildPlansList` (no other callers).
Closes#34024
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [web] Update personal-plan acceptance test for new buildPlansList shape
The previous test asserted `buildPlansList().individualMonthlyPlans`,
which no longer exists after the change-plan modal reorder dropped the
per-period buckets. Move the assertion to
`buildPlansListForSubscriptionDash()`, which is where the personal-plan
exclusion is now enforced (via `CHANGE_PLAN_MODAL_PLAN_CODES`).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [web] Drop now-dead client-side plan filter
`IndividualPlansTable` used to filter out `paid-personal`,
`paid-personal-annual` and `institutional_commons` defensively because
the old `buildPlansListForSubscriptionDash` returned every non-group
plan that wasn't `hideFromUsers`. The previous commit pins the modal to
an explicit six-plan list (`CHANGE_PLAN_MODAL_PLAN_CODES`), so none of
those plan codes ever reach the frontend and the filter is dead. Remove
it and the now-unused `useMemo` import.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Revert "[web] Drop now-dead client-side plan filter"
This reverts commit 83e8448f2cfa2c68e44b749d5a2bc350a7443c6d.
We'll do that in a later cleanup
* Swap "Student monthly" and "Student annual" for consistency
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GitOrigin-RevId: 046a235e14e7ad6622288f5a5a723f5a4f7f14da
* [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