Compare commits

...

194 commits

Author SHA1 Message Date
Antoine Clausse
52f1e46343 Fix casing in E2E tests (Example project, Blank project, ...) (#25812)
* Fix casing in Tests (Example project, Blank project, Trashed projects, ...)

* Check "Blank Project" case insentively

* Fix git-bridge tests

GitOrigin-RevId: 52339258016c3a923c6207a65d058cb0d6e9d3a2
2025-05-22 08:45:33 +00:00
Christopher Hoskin
841e32bb64 Merge pull request #25809 from overleaf/csh-issue-22789-ci-mongo-7
Upgrade the dev environment and CI to mongo 7

GitOrigin-RevId: da02881d142d21be47dac7bd2af74520ba8664cd
2025-05-22 08:45:24 +00:00
Miguel Serrano
88d3186dc1 Merge pull request #25792 from overleaf/msm-bump-multer
Bump `multer` to v2.0.0

GitOrigin-RevId: 688bfd3e6546b18f22ebaef82e4d9dd57b6d40bd
2025-05-22 08:45:16 +00:00
Rebeka Dekany
f86eb6208f Filter out link-sharing token sent to Sentry (#25787)
GitOrigin-RevId: 647f1a2e20e7883f7ab9c862bb0d90cf96360c24
2025-05-22 08:08:13 +00:00
Eric Mc Sween
c18b3f95b2 Merge pull request #25492 from overleaf/em-paginate-changes-1
Paginate history changes endpoint

GitOrigin-RevId: 2b48044d64244404efcd2e090b682c1f571a5567
2025-05-22 08:08:09 +00:00
Jimmy Domagala-Tang
23e24627d5 Merge pull request #25821 from overleaf/jdt-handle-no-prem-src
Handle cases where Writefull is not defined on a user on the subscription page

GitOrigin-RevId: ef43da630b5194f6021ebfc52ca4cb473e674b23
2025-05-22 08:08:05 +00:00
Jimmy Domagala-Tang
d6cd041704 Merge pull request #25505 from overleaf/jdt-redirect-to-wf-based-on-prem-src
Manage on Writefull should provide the right instructions based on premiumSource

GitOrigin-RevId: bc6dcc5962d18220c445315acbb3b4040ff23d5d
2025-05-22 08:08:01 +00:00
Antoine Clausse
e0f3bea9ad [web] De-capitalize english translations (#24123)
* Create decapitalize.sh script

* Remove `text-capitalize` classes, rely on translations instead

* `Account Linking` -> `Account linking`

* `Account Settings` -> `Account settings`

* `Add Affiliation` -> `Add affiliation`

* `Add Email` -> `Add email`

* `Add Files` -> `Add files`

* `Add to Dictionary` -> `Add to dictionary`

* `All Projects` -> `All projects`

* `All Templates` -> `All templates`

* `Archive Projects` -> `Archive projects`

* `Archived Projects` -> `Archived projects`

* `Auto Compile` -> `Auto compile`

* `Back to Subscription` -> `Back to subscription`

* `Blank Project` -> `Blank project`

* `Change Password` -> `Change password`

* `Change Project Owner` -> `Change project owner`

* `Clear Sessions` -> `Clear sessions`

* `Company Name` -> `Company name`

* `Compile Error Handling` -> `Compile error handling`

* `Compile Mode` -> `Compile mode`

* `Compromised Password` -> `Compromised password`

* `Confirm Affiliation` -> `Confirm affiliation`

* `Confirm Email` -> `Confirm email`

* `Connected Users` -> `Connected users`

* `Contact Sales` -> `Contact sales`

* `Contact Support` -> `Contact support`

* `Contact Us` -> `Contact us`

* `Copy Project` -> `Copy project`

* `Delete Account` -> `Delete account`

* `Emails and Affiliations` -> `Emails and affiliations`

* `Git Integration` -> `Git integration`

* `Group Settings` -> `Group settings`

* `Link Accounts` -> `Link accounts`

* `Make Primary` -> `Make primary`

* `Mendeley Integration` -> `Mendeley integration`

* `Papers Integration` -> `Papers integration`

* `Project Synchronisation` -> `Project synchronisation`

* `Sessions Cleared` -> `Sessions cleared`

* `Stop Compilation` -> `Stop compilation`

* `Update Account Info` -> `Update account info`

* `the Sales team` -> `the sales team`

* `your Group settings` -> `your group settings`

* `Zotero Integration` -> `Zotero integration`

* Update decapitalize.sh

* Decapitalize some translations

* `Example Project` -> `Example project`

* `New Project` -> `New project`

* `New Tag` -> `New tag`

* `Trashed Projects` -> `Trashed projects`

* `Upload Project` -> `Upload project`

* `Your Projects` -> `Your projects`

* Revert "Create decapitalize.sh script"

This reverts commit 8c79f367096c206c704c7c01e3572a18f3961d5e.

* Revert changes to stories

* Fix tests

* `Contact us of` -> `Contact us if`

* Make `Contact us` bold in tex files

* `sales team` -> `Sales team`

* `Link accounts and Add email` -> `Link accounts and add email`

* `Make Private` -> `Make private`

* `contact support` -> `contact Support`

* Make `Make primary` tests case sensitive

* Use `add_email` translation string

* Revert changes to non-english locales

* Remove redundant `Account settings` translation

* `New project Name` -> `New project name`

GitOrigin-RevId: 675c46f96ddbf3d259a8d723fed62aa4a7ed40b7
2025-05-22 08:07:46 +00:00
Antoine Clausse
436dcc977f Update Node to 22.15.1 (#25785)
GitOrigin-RevId: 52428d2d7e67c3135a1604fa487dd142aa08bf15
2025-05-22 08:07:42 +00:00
Antoine Clausse
b667cef262 Revert "Update defaultHighWaterMark to 64KiB (Node 22's default) (#25522)" (#25789)
This reverts commit 19d731abf683066654027de3a4f9ac0b8916f22c.

GitOrigin-RevId: eb7c45ab45e02054601b607a4bfeb432424a1837
2025-05-22 08:07:38 +00:00
Kristina
8e6d1d5f07 Merge pull request #25732 from overleaf/kh-stripe-preview-addon-purchase
[web] add support for previewing add-on changes for Stripe

GitOrigin-RevId: 46e7d0b96bf0935a4a3afcaf03d7a6f3c26d2108
2025-05-22 08:07:20 +00:00
Domagoj Kriskovic
9b27ed4798 Reinitialise Writefull toolbar after buying AI assist (#25741)
* Reinitialise Writefull toolbar after buying AI assist (#25596)

* Reinit Writefull toolbar after buying AI assist

* use refreshSession()

* add a timeout

* add a second refresh

* Increase a timeout for second refresh of writefull session (#25725)

GitOrigin-RevId: 7247ae45ca7de7f1f3778b1b22f49e2ff840a7ef
2025-05-22 08:07:16 +00:00
Domagoj Kriskovic
b8e391c005 Handle undefined user features in UserFeaturesProvider
GitOrigin-RevId: 70841809f691e9f20591bdf1ea05c510a44892af
2025-05-22 08:07:11 +00:00
Alf Eaton
827fb19df7 Define Change.toRaw result as RawChange (#25676)
GitOrigin-RevId: 0fa23806e9d7ee015b5a2a542d52382499edf9ab
2025-05-22 08:07:07 +00:00
Alf Eaton
80897001a5 Add review mode tutorial popover (#25709)
GitOrigin-RevId: bf2a365b21da780786f2736efb0770cea5f5b656
2025-05-22 08:07:03 +00:00
Mathias Jakobsen
8a1cdab27e Merge pull request #25755 from overleaf/mj-ide-collaborators-look
[web] Align online user design to Figma

GitOrigin-RevId: 89e09056558d98a57d3c1e5a8409476530784b26
2025-05-22 08:06:55 +00:00
Mathias Jakobsen
e98addf33a Merge pull request #24979 from overleaf/mj-editor-event-hook
[web] Introduce React hook wrapper around sendMB and friends

GitOrigin-RevId: 3c693ae609c6d4e5ba280c45096692aca47975ca
2025-05-22 08:06:51 +00:00
David
0b9cb185fa Merge pull request #25740 from overleaf/dp-gutter-error-logs
Correctly open logs when using AI assist gutter button in new editor

GitOrigin-RevId: 2700832f9e18d10ca3e6ee52841d31613fee626c
2025-05-22 08:06:47 +00:00
David
061f10a059 Merge pull request #25752 from overleaf/dp-delete-multiple-files
Add bulk delete button to file tree toolbar

GitOrigin-RevId: c857d8f5027eddb29b1ca324efe1a0e94ef4c28b
2025-05-22 08:06:42 +00:00
David
c45bca6ce9 Merge pull request #25780 from overleaf/dp-equation-preview-copy
Update copy in equation preview disable modal for new editor

GitOrigin-RevId: 51f1c00764ed3cb8f48448846e575ca738f71238
2025-05-22 08:06:38 +00:00
Eric Mc Sween
17d1b0b8d6 Merge pull request #25646 from overleaf/em-ds-mobile-app-compile
Compile endpoint for the DS mobile app

GitOrigin-RevId: 2fd9f4a6e8c2ed4ee868b0c1293f6760b9d113c8
2025-05-21 08:06:36 +00:00
Miguel Serrano
5a0f53654f Merge pull request #25021 from overleaf/msm-hotfix-5-4-1
CE/SP Hotfix `5.4.1`

GitOrigin-RevId: f88fb2bef6d096cb46eb0b39652e751056d114ef
2025-05-21 08:06:20 +00:00
M Fahru
0e54e650e3 Merge pull request #25706 from overleaf/mf-tear-down-nudge-annual-checkout-page
[web] Tear down `nudge-annual-checkout-page` split test and keep the default version

GitOrigin-RevId: 5714810b2a8abedca60855b37b059cd7f900407c
2025-05-21 08:06:16 +00:00
M Fahru
6a73d3f8f3 Merge pull request #25705 from overleaf/mf-add-journal-grey-sticker
[web] Add `journal-grey.svg` sticker in Contentful

GitOrigin-RevId: 713ba7ef1e2589eecb9b93081d31a79464172850
2025-05-21 08:06:07 +00:00
Jakob Ackermann
47b76a49d8 [web] start fetching load global blobs on module import (#25757)
GitOrigin-RevId: 7c1b6ed717142ad07d6ba5464aab2ecc6ebe9736
2025-05-21 08:05:59 +00:00
Jessica Lawshe
6bc4e40773 Merge pull request #24624 from overleaf/jel-latexqc-updates
[LaTeXQC] Footer and other minor style updates

GitOrigin-RevId: 67a43f715857a3bd1e97f24278d8e4586815688c
2025-05-21 08:05:50 +00:00
Jakob Ackermann
26a7a7d7b8 [clsi] mark VM as unhealthy when detecting of-of-disk condition (#25721)
* [clsi] shed load when detecting out-of-disk condition

* [clsi] mark VM as unhealthy when detecting of-of-disk condition

GitOrigin-RevId: 25cda6785c0d973f50ec6206bee389804f35917e
2025-05-21 08:05:34 +00:00
Davinder Singh
bb24aa46d1 [B2C] Bootstrap 5 migration of why-latex page (#25133)
* adding temporary rendering of the BS5 version of why-latex page

* adding first section on the page with new styling, that is compatible with BS5

* adding next section

* adding cards and copy pasting existing styling

* using variables instead of direct values

* fixing the styling of h3 in info-card

* adding next section and its styling

* adding variables

* adding features card section

* adding the next features card

* adding the next features card section

* adding another card section

* adding last feature card section

* adding next section

* adding next section

* adding next section

* adding begin now card

* running npm run lint:styles:fix

* making some style changes to match BS3 version for smaller screen under lg in BS5

* adding a width fix to image

* changing breakpoints to bring consistency in stylesheet

* adding vars

* adding split test

* removing the temporary rendering solution for the BS5 page

* adding splitTestHandler Stub

GitOrigin-RevId: 1257dff09e5371d68e102972e3544559800ca339
2025-05-21 08:05:30 +00:00
Brian Gough
efd55ffe97 Merge pull request #25743 from overleaf/bg-deactivate-projects-script
add deactivate projects script

GitOrigin-RevId: 5acf4b980d8980457930ee488571362da2a8014c
2025-05-21 08:05:25 +00:00
David
1354465562 Merge pull request #25727 from overleaf/dp-fix-track-changes-e2e-tests
Fix broken E2E tests after reviewer role feature flag cleanup

GitOrigin-RevId: 9860d546d8a6385554f223bf15c10875089ea130
2025-05-21 08:05:20 +00:00
Jakob Ackermann
1e6b13f9d5 [history-ot] rename remaining history-v1-ot references to history-ot (#25428)
* [history-ot] rename remaining history-v1-ot references to history-ot

* [web] rename History-v1 OT -> History OT in admin panel

* [web] rename OT Migration -> History OT Migration in admin panel

GitOrigin-RevId: 103ce816d5320d6379d51009cdc08b8a71aa48e6
2025-05-20 08:06:46 +00:00
Jakob Ackermann
f56645ecfe [server-ce] develop: fix mismatching bind-mount and env for clsi output (#25761)
GitOrigin-RevId: e907bc183360d253f446ed304108974d1f0b034d
2025-05-20 08:06:41 +00:00
Jakob Ackermann
efc42481da [clsi] avoid creating legacy db folder (#25760)
GitOrigin-RevId: eaa97813f0e20d14d7d6dafefe7b8b4d002fa41c
2025-05-20 08:06:36 +00:00
CloudBuild
26f27d32a1 auto update translation
GitOrigin-RevId: 8d2e4b1682fe0735260ca5f48cf5617966497fa9
2025-05-20 08:06:31 +00:00
M Fahru
14d6600fb5 Merge pull request #22908 from overleaf/mf-fix-disable-element-bs5-anchor-tag
[web] Fix `disableElement` won't properly disable the element if using bs5 and applied on anchor tag

GitOrigin-RevId: 49ce8514be3e44e5e3a45f41751c94c77f34399b
2025-05-20 08:06:26 +00:00
roo hutton
d8c5b74e09 Merge pull request #24855 from overleaf/rh-pug-contact-ui
Pug BS5 contact form UI updates

GitOrigin-RevId: 2a2428c89f799913ad5c0f7a607d59735334aeda
2025-05-20 08:06:07 +00:00
roo hutton
d680544b69 Merge pull request #24787 from overleaf/rh-sort-account-emails
Sort user emails by primary>confirmed>alphabetical

GitOrigin-RevId: 1d166e424e3848b83110c1a87adfff7790c1a01f
2025-05-20 08:06:00 +00:00
Domagoj Kriskovic
ab37e18bc3 Update AI Assist wording on checkout page if not in rollout (#25689) (#25733)
* Update AI Assist wording on checkout page if not in rollout

* update wording when buyin addon

GitOrigin-RevId: 7133b4fd3efac8e8a7361dcc15d54367f809f16d
2025-05-20 08:05:36 +00:00
Kristina
dbb528762e [web] add support for previewing base plan changes for Stripe (#25619)
GitOrigin-RevId: 458eeac52bc5fc010b9749f6fcd48350aa792582
2025-05-20 08:05:31 +00:00
Miguel Serrano
ecdd0c54bd [CE/SP] Update base image to noble-1.0.2 and node@22 (#25716)
* [CE/SP] Update base image to node:22

Also triggers a rebuild of the image to ensure all dependencies are up to date

* Bump phusion image to noble-1.0.2

GitOrigin-RevId: 8dce9d3cc6e8df28fce7a15f2727e7bc4aa453fd
2025-05-19 12:27:23 +00:00
Alf Eaton
f7d37a49d6 Upgrade CodeMirror dependencies (#25620)
* Upgrade CodeMirror dependencies
* Upgrade Lezer dependencies

GitOrigin-RevId: fcbf9b4bbf2577d85f44b48d3b745a56e49e24c9
2025-05-19 12:27:19 +00:00
Alf Eaton
ed006b707c Update "Editing" role description (#25641)
GitOrigin-RevId: dba2e4a21ca645ba34d9e41b76f09a287b5c3b33
2025-05-19 12:27:14 +00:00
Alf Eaton
bb3f1aa998 Merge pull request #25666 from overleaf/ae-reviewing-button
Prevent gap between button and menu

GitOrigin-RevId: 42f6a80ea2cda55c3b321a8d9ca9710ecf06c8a3
2025-05-19 12:27:09 +00:00
Alf Eaton
d280d4ecad Merge pull request #25691 from overleaf/ae-project-list-nav
Move isReady out of DefaultNavbar component

GitOrigin-RevId: 66f19620399e405c9ef4d95f7aef3ab918da5aa1
2025-05-19 12:27:05 +00:00
Domagoj Kriskovic
b375b13950 Revert "Reinitialise Writefull toolbar after buying AI assist" (#25731)
* Revert "Increase a timeout for second refresh of writefull session (#25725)"

This reverts commit 0a34bdde656ade863aead22f003253e13af37829.

* Revert "Reinitialise Writefull toolbar after buying AI assist (#25596)"

This reverts commit a2572d62bce0e344d92696e42d137a0b36574b3b.

GitOrigin-RevId: 3d51a4375059ab9f4494a7e18b132cc5db34e4cd
2025-05-19 12:27:00 +00:00
Mathias Jakobsen
60e588440f Merge pull request #25631 from overleaf/mj-reactdom-render
[web] Remove ReactDOM.render usage

GitOrigin-RevId: 42f62fa79a784cf3cc5c420357880154562d7dc7
2025-05-19 12:26:56 +00:00
Mathias Jakobsen
5ee59a4f4a Merge pull request #25548 from overleaf/mj-add-booktabs
[web] Add support for booktabs table style

GitOrigin-RevId: e3f7e1a867474a86e4b5f8c701d845d55592bb68
2025-05-19 12:26:48 +00:00
Miguel Serrano
a8b443fe5f [web] Update base-x dependency to 4.0.1 (#25581)
GitOrigin-RevId: 746f06a3abe75dbc7deb6ea181a15dfc24cd9d22
2025-05-19 12:26:43 +00:00
Domagoj Kriskovic
996c407393 Revert "Update AI Assist wording on checkout page if not in rollout (#25689)" (#25726)
This reverts commit 20a90b14e97b1a8837e8be697c1a9666ed15a1c3.

GitOrigin-RevId: 26d4ad8f1b3a7dbe884dfbe4f4be5ee632abed1e
2025-05-19 12:26:35 +00:00
Miguel Serrano
85533a36e9 [history-v1] Disable backups on CE/SP (#25591)
Disables backup when `backupStore` is not present,
as it's the case for CE/SP

GitOrigin-RevId: a920f041c639e599084fa97d2ef2643a01da70e3
2025-05-19 12:26:30 +00:00
Domagoj Kriskovic
d7ef7f0399 Update AI Assist wording on checkout page if not in rollout (#25689)
* Update AI Assist wording on checkout page if not in rollout

* update wording when buyin addon

GitOrigin-RevId: 20a90b14e97b1a8837e8be697c1a9666ed15a1c3
2025-05-19 12:26:26 +00:00
Domagoj Kriskovic
50a5c7984d Reinitialise Writefull toolbar after buying AI assist (#25596)
* Reinit Writefull toolbar after buying AI assist

* use refreshSession()

* add a timeout

* add a second refresh

GitOrigin-RevId: a2572d62bce0e344d92696e42d137a0b36574b3b
2025-05-19 12:26:21 +00:00
Miguel Serrano
cc3b020d88 [CE/SP] cron for daily runs of scripts/flush_all.js (#25575)
* [CE/SP] `cron` for daily runs of `scripts/flush_all.js`

GitOrigin-RevId: 9616e99c01491e2a410601f4e33917ed47990b11
2025-05-19 12:26:16 +00:00
Rebeka Dekany
957462b61c Update selector to target input[type='search'] (#25712)
GitOrigin-RevId: 492bda0eb70dd821dbfa3dbf818cafc1ef8975eb
2025-05-19 12:26:12 +00:00
CloudBuild
c4c8f521ff auto update translation
GitOrigin-RevId: 07588ad1e4cbc9028cf0de125b4c6c222e1b0ecc
2025-05-19 08:05:37 +00:00
M Fahru
7a0a6077cf Merge pull request #25692 from overleaf/mf-add-stickers-cms
[web] Add pen-yellow and support-green sticker in contentful

GitOrigin-RevId: 26beffd1bf75f9fdf1dba5b8e93b1190a642ff6d
2025-05-19 08:05:33 +00:00
Andrew Rumble
586820c34d Fix package version for socket.io
GitOrigin-RevId: 07a436ce0db5a0cd320964e3e9e7a5646877561b
2025-05-19 08:05:29 +00:00
Jakob Ackermann
18cd52cfa1 [real-time] avoid shutting down all pods simultaneously (#25627)
GitOrigin-RevId: e416e06588b915548c83d70433f411c9f303ad87
2025-05-19 08:05:25 +00:00
Jakob Ackermann
0e13796882 [real-time] bail out early upon hitting a redis error (#25614)
GitOrigin-RevId: 2563094d1ec8017450fdfdb2b0e77d74bbc825d1
2025-05-19 08:05:21 +00:00
Andrew Rumble
daa52d62fa Allow an empty origin request in real-time
This will only happen with a same-origin request (or if someone has
tampered with the request - in which case they could set anything).

Co-authored-by: Tim Down <158919+timdown@users.noreply.github.com>
GitOrigin-RevId: 9dfe49f974a476bfe215768d3984dd60a381d37a
2025-05-19 08:05:16 +00:00
Jakob Ackermann
e3e8d944b2 [web] fetch project members in a single db query (#25662)
* [web] fetch project members in a single db query

GitOrigin-RevId: ca749327d4783c67a3ad81f611cd7d3e7fa84028
2025-05-19 08:05:12 +00:00
Jakob Ackermann
14cbd44d9b [web] deletedDocs are not needed for joinProject anymore (#25654)
* [web] deletedDocs are not needed for joinProject anymore

* [web] cleanup unit tests

GitOrigin-RevId: 91c9bc60ec776757b3031cbc85c67ae1bf4adf4d
2025-05-19 08:05:08 +00:00
Jakob Ackermann
cb7d75202b [web] fetch users subscriptions once from project dashboard (#25652)
* [web] fetch users subscriptions once from project dashboard

* [web] fix types

GitOrigin-RevId: 18de18f8d4237d97087ef92eaa5052f253a92813
2025-05-19 08:05:04 +00:00
Jakob Ackermann
bc78432e62 [web] wait for prefetching of projects listing (#25650)
GitOrigin-RevId: 59fb0c74b8cf6a496e256960f7f2e83ace2c5ee0
2025-05-19 08:04:59 +00:00
CloudBuild
efa39ee664 auto update translation
GitOrigin-RevId: aaa30f0991b037c3829cebc655e1cd9086b6cba5
2025-05-16 08:07:20 +00:00
M Fahru
1440a47d53 Merge pull request #25560 from overleaf/mf-stripe-analytics-invoice-event
[web] Handle stripe analytics for the `subscription-invoice-collected` event

GitOrigin-RevId: cba56db820cac92a66307a05350c779e1198cbf3
2025-05-16 08:07:16 +00:00
M Fahru
81dd3c10a7 Merge pull request #25497 from overleaf/mf-send-subscription-renewed-event-stripe
[web] Send analytics events and user properties when user's subscription is renewed with the same plan

GitOrigin-RevId: c21436d942e8b1a2b8c9fca5827826bf0e8b8bdb
2025-05-16 08:07:12 +00:00
M Fahru
8017918063 Merge pull request #25490 from overleaf/mf-send-subscription-cancelled-and-reactivated-event-stripe-subscription
[web] Send analytics events and user properties for cancelled and reactivated event in Stripe subscription

GitOrigin-RevId: 07a4e6395be334c90910b5d421624c4daa703d3b
2025-05-16 08:07:04 +00:00
M Fahru
75ce58d0c6 Merge pull request #25404 from overleaf/mf-send-subscription-analytics-events
[web] Send analytics events and user properties when user start subscription using Stripe

GitOrigin-RevId: 9028397a5cb256df506e14beb1705191c9ae3f7f
2025-05-16 08:06:57 +00:00
Rebeka Dekany
bb66f75027 Add aria-label to the documentation searchbar and update the type to search (#25431)
GitOrigin-RevId: 782eb2238636040fedae628b17224f2e91159a34
2025-05-16 08:06:52 +00:00
Rebeka Dekany
3ef62472bd Fix back to your projects button (#25500)
GitOrigin-RevId: 98f84593bec190b24a225d4690414e4e9f1141e0
2025-05-16 08:06:48 +00:00
Rebeka Dekany
e282a74f7a Make links more descriptive on the Account settings page (#25558)
GitOrigin-RevId: 21cb7c02f7a5678b4c385da5b842ad6a5303169b
2025-05-16 08:06:44 +00:00
Antoine Clausse
10091811f7 Remove returns in functions with callback in CooldownManager (fix DeprecationWarning) (#25665)
GitOrigin-RevId: 3652ee78d533cb00ce5ec4de1a66a959ab418def
2025-05-16 08:06:33 +00:00
Antoine Clausse
67ab5a749a Update Node to 22.15.0 (#24699)
* Run `bin/update_node 20.18.2 22.15.0`

* Remove expects on `fetchMock.callHistory.done()` to fix tests: are they necessary?

* Set node version to `22.x` in linked-url-proxy

* Increase test timeout to 30s in `github-sync`, Add waiting steps

* Define `navigator.onLine` in tests setup

GitOrigin-RevId: 75eb556e9f51b665e57497a0879b6915d14069ce
2025-05-16 08:06:26 +00:00
Eric Mc Sween
2dd054d602 Merge pull request #25606 from overleaf/em-o-error-types
OError: handle unknown error types
GitOrigin-RevId: a52dd92a4f95cd738556612599805f41f24de69f
2025-05-16 08:06:22 +00:00
David
966cea3d8b Merge pull request #25550 from overleaf/dp-share-modal-proptypes
Remove proptypes from ShareProjectModal

GitOrigin-RevId: b95fed5007f72e4a57a65b1d08d8fcc9579b3630
2025-05-16 08:06:05 +00:00
David
b56556f37b Merge pull request #25547 from overleaf/dp-remove-reviewer-role-flag-frontend
Clean up reviewer-role feature flag from frontend

GitOrigin-RevId: 0cac59be58b0350c24f57d3e63898246b2bd6881
2025-05-16 08:06:00 +00:00
David
899f6d18d6 Merge pull request #25617 from overleaf/dp-projec-owner-email-overflow
Truncate long project owner names in project dashboard

GitOrigin-RevId: a3c98b359dc880a3f487c1a6de9a2fe4bb4913c1
2025-05-16 08:05:56 +00:00
David
449a5d6339 Merge pull request #25605 from overleaf/dp-track-changes-redirect
Redirect old track changes marketing page to track changes learn wiki page

GitOrigin-RevId: 890e7f746b71b8e5108e8209d55903f68adde1ea
2025-05-16 08:05:52 +00:00
David
4847c83cb8 Merge pull request #25618 from overleaf/dp-symbol-palette-proptypes
Remove Proptypes from SymbolPalette components

GitOrigin-RevId: 58b74652a5b47612c4622a7cac9b1ff3aadadfc5
2025-05-16 08:05:48 +00:00
David
69d99079b1 Merge pull request #25553 from overleaf/dp-clone-project-modal-proptypes
Remove Proptypes from CloneProjectModal

GitOrigin-RevId: 400f4c9de72eb1910a0ca067882a6358663303d3
2025-05-16 08:05:44 +00:00
Antoine Clausse
fee5ea8411 Remove returns of promises within functions with callbacks (address DeprecationWarning) (#25603)
* [document-updater] Don't return promises within functions with callbacks

Remove the errors:
DeprecationWarning: Calling promisify on a function that returns a Promise is likely a mistake
https://cloudlogging.app.goo.gl/YHDhoarvLEw2w9rXA

* Remove some more unnecessary returns in functions with callbacks, for consistency

* Add `sendCanaryAppliedOp` to excluded methods for promisification

GitOrigin-RevId: fa6d3e47c4e6561dc29d4c15e57c3289fc1f3dfa
2025-05-16 08:05:33 +00:00
Tim Down
5c4cb50628 Merge pull request #24988 from overleaf/td-bs5-upgrade-and-rename
Apply minor upgrades to Bootstrap 5 and react-bootstrap

GitOrigin-RevId: eb013f38515ebd4b9572d139f00841aca344e3c6
2025-05-16 08:05:28 +00:00
Tim Down
2ebc3a982a Merge pull request #25588 from overleaf/td-bs5-restricted-page
Migrate restricted page to BS5

GitOrigin-RevId: 7df26700b5e3b8fb08d061fd9e211bf09ca4e956
2025-05-16 08:05:24 +00:00
Jakob Ackermann
59f614a41b [web] use the common split-test for clsi-cache when cloning (#25644)
GitOrigin-RevId: 30377d69a9e1be11261eb6076f8996e71090fb9e
2025-05-16 08:05:07 +00:00
Jakob Ackermann
ec1bd69605 [clsi-cache] remove non sharded instances (#25645)
* Revert "[clsi-cache] only use sharding from updated project editor tabs (#25326)"

This reverts commit 1754276bed3186c0536055c983e32476cc90d416.

* [clsi-cache] remove non sharded instances

GitOrigin-RevId: aa3ac46140dfc1722a3350cf7071e5b11af61199
2025-05-16 08:05:02 +00:00
CloudBuild
40193752c4 auto update translation
GitOrigin-RevId: c67507e30704ca92838cf1b72ae911624fc66200
2025-05-14 08:07:41 +00:00
Jakob Ackermann
eebda2427e [clsi-cache] fix path traversal (#25585)
* [clsi-cache] fix path traversal

* [clsi-cache] double down on path traversal validation

Co-authored-by: Brian Gough <brian.gough@overleaf.com>

---------

Co-authored-by: Brian Gough <brian.gough@overleaf.com>
GitOrigin-RevId: 28a6a2024aae81e9b361db7918dc0c5381cd8246
2025-05-14 08:06:54 +00:00
Jakob Ackermann
e25a69936e [clsi-cache] base64 encode X-All-Files header if needed (#25579)
* [clsi-cache] base64 encode X-All-Files header if needed

* [clsi-cache] add explicit error check

Co-authored-by: Brian Gough <brian.gough@overleaf.com>

---------

Co-authored-by: Brian Gough <brian.gough@overleaf.com>
GitOrigin-RevId: bd3b6381b68398aac4a07e48cd69e6aa97e94f18
2025-05-14 08:06:49 +00:00
Jimmy Domagala-Tang
443fb3f152 Merge pull request #24739 from overleaf/dk-thankyou-page
Update "thanks for subscribing page" with AI Assist links

GitOrigin-RevId: 41a23d6fd5edfc8f9ad0f97e513e1ea66aed5bdc
2025-05-14 08:06:44 +00:00
Alf Eaton
fb0cfbe0bb Add more detail to word count UI (#25400)
GitOrigin-RevId: 3521f2ea03332e46ef1bac634ce0650cdce01249
2025-05-14 08:06:40 +00:00
Alf Eaton
bd67b4ca13 Improve review panel entry performance (#25402)
GitOrigin-RevId: 2a6ec8ad432195c6069bb58be37dd93341533817
2025-05-14 08:06:35 +00:00
Alf Eaton
6c96c70b28 Remove the full-project-search split test (#25444)
GitOrigin-RevId: b36c1c81152694547dcf044cfb2cb0f511bfdc22
2025-05-14 08:06:31 +00:00
Alf Eaton
b70e0166bd Remove zlib dependency from freegeoip (#25474)
GitOrigin-RevId: 9f61a0630ff6c4b7fd92f180fb58f91178567ede
2025-05-14 08:06:26 +00:00
Alf Eaton
60cdd252ef Add span between synctex button and tooltip (#25475)
GitOrigin-RevId: d1e7c71597566f916a9432d9114def791cf25fa8
2025-05-14 08:06:21 +00:00
Alf Eaton
c942b490ab Clamp PDF highlights to the extents of the page container (#25498)
GitOrigin-RevId: cc2e30b04b9c57b2ea6038bee1e06467b785386f
2025-05-14 08:06:16 +00:00
Jimmy Domagala-Tang
732b365683 Merge pull request #25568 from overleaf/jdt-rely-on-user-feats-for-assist-paywall-button
Rely on user features when showing the get assist paywall button post upgrade

GitOrigin-RevId: 2218171eb57996ee962b4ddc94c1749ad65b9c1b
2025-05-14 08:06:04 +00:00
Jimmy Domagala-Tang
dd351f64fb Merge pull request #25587 from overleaf/dk-select-table-size-fix
Prevent "select size" popover in TableDropdown from closing when toolbar is collapsed

GitOrigin-RevId: 82f8226e0ff071dfea965c8c991141d90ff72197
2025-05-14 08:06:00 +00:00
Jimmy Domagala-Tang
5730cd3dde Merge pull request #25577 from overleaf/dk-assist-promition-spacing-fix
Fix alignment issue in equation and table generator promotion

GitOrigin-RevId: 2f085e266b0385efcae546b89e2c73388764bae3
2025-05-14 08:05:55 +00:00
Mathias Jakobsen
b52c0bf08e Merge pull request #25534 from overleaf/mj-table-gen-color
[web] Fix table generator edited cell color

GitOrigin-RevId: 7ad762954637b13022a361f87fdf08f7dc97e17f
2025-05-14 08:05:43 +00:00
Mathias Jakobsen
587390d066 Merge pull request #25514 from overleaf/mj-ide-pdf-controls-editor-only
[web] Hide PDF controls from menu bar in editor only mode

GitOrigin-RevId: 91513e40693e1214c3bdbc56d9dec19e08c74e36
2025-05-14 08:05:38 +00:00
ilkin-overleaf
21c035b8d5 Merge pull request #25468 from overleaf/ii-flexible-licensing-invoice-date
[web] FL next invoice date formatting

GitOrigin-RevId: 5f4f86d4f11c7ee217ff806d26fc3f8a79e5affc
2025-05-14 08:05:34 +00:00
Rebeka Dekany
6d35305d7d Use the semantic <details> HTML tag instead for disclosure (#25489)
GitOrigin-RevId: 9ed634529a17abd0693441c7563262ed5d1c7f88
2025-05-14 08:05:25 +00:00
Rebeka Dekany
271635491a Remove incorrect "button" role from navigational links that are styled as buttons (#25504)
GitOrigin-RevId: 717b20a6f2e893034eb12547fa663d358c0de419
2025-05-14 08:05:21 +00:00
Antoine Clausse
aa002369cb Update defaultHighWaterMark to 64KiB (Node 22's default) (#25522)
* Set defaultHighWaterMark to 16KiB

This is already the default in Node 20

* Set defaultHighWaterMark to 64KiB

Per https://github.com/overleaf/internal/pull/25522#issuecomment-2872035192

GitOrigin-RevId: 19d731abf683066654027de3a4f9ac0b8916f22c
2025-05-14 08:05:16 +00:00
Rebeka Dekany
7c79c3b4c3 Add ARIA attributes for menu and separator (#25501)
GitOrigin-RevId: ef80d2811ecee78adc8bb359cf3b059d79fe9900
2025-05-13 08:08:36 +00:00
Rebeka Dekany
ac51878186 Improve ARIA labels for buttons and links on the Account setting page (#25499)
* Improve announced button and link labels for screen reader users

* Improve labels for integration widgets and update test

* Make integration widget IDs to be required

GitOrigin-RevId: 1e0124ef63a91fb63dffd79881c60794bccb9d27
2025-05-13 08:08:31 +00:00
Rebeka Dekany
3cb7ef05d9 Fix undefined alt text for images (#25447)
GitOrigin-RevId: 59efe870275f3dcbabecf1c3d115e7a7a85be594
2025-05-13 08:08:27 +00:00
Christopher Hoskin
7356c3b863 Merge pull request #25543 from overleaf/csh-issue-23942-more-migrate
Remove more CR refs

GitOrigin-RevId: 7ba91712943c309d40613b0f7247f20d45d7fbb1
2025-05-13 08:08:22 +00:00
Tim Down
11d964649c Merge pull request #25502 from overleaf/td-chat-open-bug
Prevent chat opening by default for new user

GitOrigin-RevId: 260050c26f6b9dee7ea52284dadb7ed00ce9eddb
2025-05-13 08:08:11 +00:00
David
8d940ad841 Merge pull request #25387 from overleaf/dp-editor-toolbar-proptypes
Remove proptypes from editor-navigation-toolbar components

GitOrigin-RevId: 77a1c4e13e3da6c06bb515b0137da2f70bfdf4a8
2025-05-13 08:08:06 +00:00
David
8e31c30ec7 Merge pull request #25398 from overleaf/dp-file-tree-proptypes
Remove PropTypes from file-tree components

GitOrigin-RevId: 7ecbf9778da59b852be8678c5dff61e13d927b9c
2025-05-13 08:08:02 +00:00
Jimmy Domagala-Tang
82e5b2c5d7 Merge pull request #25151 from overleaf/dk-use-user-features
UserFeaturesContext with cross-tab syncing via BroadcastChannel

GitOrigin-RevId: 4262719f5018f5717211851ce28b3255af65461a
2025-05-13 08:07:57 +00:00
Jimmy Domagala-Tang
2f3166aa54 Merge pull request #25517 from overleaf/dk-fix-get-error-assist-translation
Fix translation for "get_error_assist"

GitOrigin-RevId: ea9ef20b8d94e49e89cc77cc6517da25d002ba7f
2025-05-13 08:07:53 +00:00
Jimmy Domagala-Tang
8234e80931 Merge pull request #25538 from overleaf/jdt-fix-assist-interstitial-on-redesign
Add assist interstitial to editor redesign

GitOrigin-RevId: 97c2447bb6f6b47864563fac45ea8da46ca83777
2025-05-13 08:07:48 +00:00
Jimmy Domagala-Tang
3bfc3ee7ae Merge pull request #25540 from overleaf/jdt-push-assist-interstitial-higher-z-index
Fix assist promotion being hidden under error logs pane

GitOrigin-RevId: 715d82ddd98ce5e15ce2e42935526387b4c6fa1b
2025-05-13 08:07:44 +00:00
Eric Mc Sween
732b1d146e Merge pull request #25456 from overleaf/em-concurrency-handling
Add consistency constraints to the chunk store and Redis buffer

GitOrigin-RevId: 6f983ff207a13d204645e343290c94443dc537b0
2025-05-13 08:07:36 +00:00
Jimmy Domagala-Tang
bf22684e2d Merge pull request #25507 from overleaf/jdt-show-wf-src-on-admin
Add premium source for Writefull entitlment to the Admin page

GitOrigin-RevId: 937b6d588d0f9328eb450809a0cd2f0e4b0ea299
2025-05-13 08:07:03 +00:00
Jimmy Domagala-Tang
1ec12e3d88 Merge pull request #25493 from overleaf/jdt-ai-assist-entitlement-fix
Access addOnCode correctly when determining bundle entitlement

GitOrigin-RevId: c3aee15b3ef6fc1d32f24283ec848e600f0777f1
2025-05-13 08:06:59 +00:00
Jimmy Domagala-Tang
50c2d8f32f Merge pull request #25405 from overleaf/jdt-wf-rebrand-popover
Writefull Rebranded Features Editor Promotion

GitOrigin-RevId: 49beddbfa44bacf1546543e172dc8edcdb3784bc
2025-05-13 08:06:50 +00:00
Domagoj Kriskovic
b99a81cb25 Fix monthly price if billed annually for AI Assist (#25297)
* Fix monthly price if billed annually for AI Assist

* update script

* show annual price

* fix formatting

GitOrigin-RevId: e50493fa2176e6c8acb476a01a393eb940a3f1a2
2025-05-13 08:06:39 +00:00
Domagoj Kriskovic
c1f3758aa2 Add script to update null references in for readOnly_refs and pendingReviewer_refs (#25417)
* Add script to update null references in for readOnly_refs and pendingReviewer_refs

* update script to only update readOnly_refs

* clean up

* use projectAuditLogEntries to find relevant projects

* use updateOne

GitOrigin-RevId: bbeaa04b837ebb657c802598f0de72879f641bd0
2025-05-13 08:06:23 +00:00
Kristina
67a436b639 Merge pull request #25469 from overleaf/mj-paste-tables-multicol
[web] Improve borders and column definitions of pasted tables with multi-column cells

GitOrigin-RevId: fe9c44bd8ac6a34e8a8057f1a07d97771a116e1a
2025-05-13 08:06:10 +00:00
Kristina
70c26b6ed2 [web] prevent downgrade to personal upsell for stripe subscriptions (#25392)
GitOrigin-RevId: a954f42e1159e4bcc8fd06f5f6df9a53c67f9f90
2025-05-13 08:06:05 +00:00
Brian Gough
0d70223a48 Merge pull request #25482 from overleaf/bg-fix-bull-exporter-errors
retain completed and failed jobs for backup queue

GitOrigin-RevId: 7831ce2565dc493e3ce7f55001207daea2140575
2025-05-13 08:05:40 +00:00
Liangjun Song
caf8b5c3c5 Merge pull request #25329 from overleaf/ls-enable-stripe-checkout-for-group-plan
Enable stripe checkout for group subscriptions

GitOrigin-RevId: 10a579ebca789773bd2c94f8240b7b979b6e8eb0
2025-05-13 08:05:32 +00:00
Eric Mc Sween
5506e0d58e Merge pull request #25302 from overleaf/em-pkce-support-enforcement
Enforce pkceEnabled flag in OAuth configuration

GitOrigin-RevId: 8e941179017712050570f13522ec42814aa58c06
2025-05-12 08:06:11 +00:00
Mathias Jakobsen
ddfadbc474 Merge pull request #25422 from overleaf/mj-ide-rail-badges-placement
[web] Editor redesign: Improve badge locations for Rail buttons

GitOrigin-RevId: 11eef60e6ab35003b21fa1ebf0bde4588c5f7228
2025-05-12 08:05:56 +00:00
Mathias Jakobsen
3c3414a7d3 Merge pull request #25435 from overleaf/mj-review-panel-tests
[web] Add review panel cypress tests

GitOrigin-RevId: e953519fc8fed089df59970ee3c745b06d78ddfb
2025-05-12 08:05:52 +00:00
Brian Gough
9762cf95e3 Merge pull request #25463 from overleaf/bg-history-redis-fix-logging-in-expire-worker
reduce expire_redis_chunks log verbosity in production

GitOrigin-RevId: afcf6edc7154d49714bc60c276c129d70eaa49c7
2025-05-12 08:05:44 +00:00
Jakob Ackermann
bc4550c1f9 [CI] temporarily disable flaky tests (#25443)
GitOrigin-RevId: 4ed83e7b79d7aee0d7fab4594d4f7c8697e0cab4
2025-05-12 08:05:28 +00:00
Jakob Ackermann
fba8f776a1 [web] avoid trying to fetch synctex.gz from clsi-cache in free projects (#25445)
* [web] avoid trying to fetch synctex.gz from clsi-cache in free projects

* [clsi] parse boolean query parameter

GitOrigin-RevId: 99c98aac8147a626b704e9a888b7fc660cc5ab17
2025-05-12 08:05:24 +00:00
Brian Gough
9e07549ecb Merge pull request #25449 from overleaf/bg-histoy-redis-refactor-expire-worker
refactor the expire worker to make it easier to extend

GitOrigin-RevId: 7b277b243ed51ab3b46316d98b7157af95a9e42b
2025-05-12 08:05:19 +00:00
CloudBuild
0a0dc13030 auto update translation
GitOrigin-RevId: 4dbc6d69264f37aa2532aab2a92db943f90e0947
2025-05-09 08:06:31 +00:00
M Fahru
5ba31ab14f Merge pull request #25363 from overleaf/mf-stripe-webhook-delete-subscription
[web] Delete "expired" subscription in Stripe (in Stripe, this is called "canceled" status)

GitOrigin-RevId: 847cf431c2f6edd7ec6c4e17137d163e450dc4f1
2025-05-09 08:06:26 +00:00
M Fahru
c50bd6af89 Merge pull request #25372 from overleaf/kh-support-canceling-pending-stripe-change
[web] cancel pending Stripe subscription change

GitOrigin-RevId: c1d21a7d1c3962c20d589b1dd10f6c2a4c8e4be4
2025-05-09 08:06:22 +00:00
Eric Mc Sween
391fca9e83 Merge pull request #25361 from overleaf/em-load-latest-raw
Rename loadLatestRaw() to getLatestChunkMetadata()

GitOrigin-RevId: e089dcfa57cbbc43df8666b51eca0d81d595a5a7
2025-05-09 08:06:14 +00:00
Eric Mc Sween
5717ea7f5c Merge pull request #25306 from overleaf/em-redis-buffer-read-operations
Add changes from Redis when reading chunks from the chunk store

GitOrigin-RevId: c0ebf0669b91eb2efc5d1091d025e81efdff9fe4
2025-05-09 08:06:09 +00:00
Eric Mc Sween
7ea1b690f2 Configure PKCE support in OAuth clients (#25300)
This flag will control whether or not a particular client is allowed to
use PKCE instead of a client secret when requesting an access token.

GitOrigin-RevId: b9471112a485233308410e0cb7f20e20a613a971
2025-05-09 08:06:04 +00:00
Jakob Ackermann
d489e35782 [web] emit event when synctex mapping was downloaded from clsi-cache (#25424)
* [clsi] tell frontend when synctex mapping was downloaded from clsi-cache

* [web] emit event when synctex mapping was downloaded from clsi-cache

GitOrigin-RevId: 1f6b7e0faaa7dd76449aad566802da971a4cf9ed
2025-05-09 08:06:00 +00:00
Jakob Ackermann
8d4f258494 [web] retry fetching initial compile from cache response (#25436)
* [web] move building of compile from cache response into manager

* [web] retry fetching initial compile from cache response

GitOrigin-RevId: b4dc89f1b91d99e869c0c7789881dc72d8a5761f
2025-05-09 08:05:55 +00:00
Brian Gough
dc73a18ca4 Merge pull request #25432 from overleaf/em-redis-buffer-strict-apply
Use strict validation for the Redis buffer

GitOrigin-RevId: 43e73af5deabbf3de9f5eed14f062acc5fa35e36
2025-05-09 08:05:50 +00:00
Brian Gough
9cf284aefa Merge pull request #25414 from overleaf/bg-history-only-log-content-mismatch-once-per-request
log warning for content hash mismatch only on first occurrence

GitOrigin-RevId: ff09f8c262461488bd564ea0644d414bb32ff17e
2025-05-09 08:05:46 +00:00
Jakob Ackermann
3242376d19 [server-ce] add notice for CE users on disabling sandboxed compiles (#25425)
Co-authored-by: Mathew Evans <matt.evans@overleaf.com>
GitOrigin-RevId: 977625975af6ac68a33356dc4c39af98791e8708
2025-05-09 08:05:34 +00:00
David
2ea03af559 Merge pull request #25411 from overleaf/dp-clone-project-translation
Add missing translation for clone project modal name placeholder

GitOrigin-RevId: 7ee99d811f31eaa0441d2e9b9f579f29ff1cb368
2025-05-09 08:05:29 +00:00
Mathias Jakobsen
1b5d31941e Merge pull request #25383 from overleaf/mj-ide-long-title
[web] Editor redesign: Allow project name to shrink

GitOrigin-RevId: 4d25291437fae9672f0d0d4d20bde269f771020a
2025-05-09 08:05:25 +00:00
Mathias Jakobsen
9cb2b48c1e Merge pull request #25373 from overleaf/mj-reorder-tpr
[web] Reorder third party reference managers

GitOrigin-RevId: 283d50674fdcc60b7a32e4e7846c6638c591937a
2025-05-09 08:05:20 +00:00
Brian Gough
6eada92966 Merge pull request #25406 from overleaf/em-content-hash-validation-resync
Resync project when content hash validation fails

GitOrigin-RevId: ea9b5a78f89c55276fd67835bc262717bc778e92
2025-05-09 08:05:12 +00:00
ilkin-overleaf
2ccdb74d20 Merge pull request #25318 from overleaf/ii-flexible-licensing-manually-collected-3
[web] Add seats feature for manually collected subscriptions improvements

GitOrigin-RevId: 4fbd93097590d97ad6464d1988471a78bf7cb9e2
2025-05-09 08:05:07 +00:00
CloudBuild
d39d92cce8 auto update translation
GitOrigin-RevId: b57698529938bdf3227696cf8fbfde7f763a43d5
2025-05-08 08:06:55 +00:00
M Fahru
0335367c75 Merge pull request #25296 from overleaf/kh-support-upgrading-stripe-subscription
[web] support upgrading Stripe subscription

GitOrigin-RevId: 2663ca8f1c028a45cf47d3ab37c387c4f4b39f9a
2025-05-08 08:06:47 +00:00
M Fahru
fa553128a4 Merge pull request #25289 from overleaf/kh-rm-dead-coupon-code
[web] rm unused couponCode parameter

GitOrigin-RevId: c8c262322d74214e43870e67758aaa98aaa60c79
2025-05-08 08:06:42 +00:00
Jakob Ackermann
b3a1341545 [web] settle on a single split-test for the clsi-cache rollout (#25399)
* [web] settle on a single split-test for the clsi-cache rollout

Use the split-test that was used for rolling out the writes so that we
can use their already populated caches.

* [clsi-cache] fix non-sharded clsi-cache in dev-env

GitOrigin-RevId: 6ebd6369183342fe6d5e325b760d011fd1d57516
2025-05-08 08:06:37 +00:00
Jessica Lawshe
4b5f31ac95 Merge pull request #25353 from overleaf/revert-25351-revert-24919-jel-create-group-audit-log
Revert "Revert "[web] Add group audit log""

GitOrigin-RevId: 4d61cfd9e8a7dac1f5837a4028aff95fa19c308a
2025-05-08 08:06:32 +00:00
Brian Gough
ad94c29659 Merge pull request #25391 from overleaf/em-queue-changes-verification-rollout-stage-2
queue changes verification rollout stage 2

GitOrigin-RevId: c79a5a252c6fc8caf6fd164a31e6e360b6fc3e73
2025-05-08 08:06:27 +00:00
Brian Gough
ec91c120b1 Merge pull request #25284 from overleaf/em-queue-changes-verification
Exercise the Redis buffer when persisting changes

GitOrigin-RevId: a649b9808b6472e7c5dd9c8bfa6e3c98fb6ef4d4
2025-05-08 08:06:22 +00:00
Jimmy Domagala-Tang
9f0f910a83 Merge pull request #25251 from overleaf/jdt-show-wf-provided-bundle-on-free-plans
Show AI Assist entitlment via Writefull on free user's subscriptions page

GitOrigin-RevId: 20a456a231f60df279b949057972125735166904
2025-05-08 08:06:14 +00:00
Jimmy Domagala-Tang
fbbba7a3df Merge pull request #24816 from overleaf/jdt-update-checkout-for-bundle
Update checkout pages for AI Assist bundle content

GitOrigin-RevId: e2e1b705dd92e0858835d18eb6d8c5750030e550
2025-05-08 08:06:09 +00:00
Jimmy Domagala-Tang
6973ba4244 Merge pull request #25090 from overleaf/jdt-align-wf-rebrand-split-test
Align Writefull bundle changes to same split test

GitOrigin-RevId: 28eb7c0835a38d4989461d941efc3e8c0cdcfecb
2025-05-08 08:06:04 +00:00
Jakob Ackermann
e8b5ee2ff9 [history-ot] initial implementation of using doc-level history-ot (#25054)
* [history-v1-ot] initial implementation of using doc-level history-v1-ot

* [web] fix advancing of the otMigrationStage

Use 'nextStage' for the user provided, desired stage when advancing.

Co-authored-by: Brian Gough <brian.gough@overleaf.com>

* [document-updater] document size check in editor-core

* [history-ot] rename history-v1-ot to history-ot and add types

* [history-ot] apply review feedback

- remove extra !!
- merge variable assignment when processing diff-match-match output
- add helper function for getting docstore lines view of StringFileData

Co-authored-by: Alf Eaton <alf.eaton@overleaf.com>

* Revert "[document-updater] add safe rollback point for history-ot (#25283)"

This reverts commit d7230dd14a379a27d2c6ab03a006463a18979d06

Signed-off-by: Jakob Ackermann <jakob.ackermann@overleaf.com>

---------

Signed-off-by: Jakob Ackermann <jakob.ackermann@overleaf.com>
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
Co-authored-by: Alf Eaton <alf.eaton@overleaf.com>
GitOrigin-RevId: 89c497782adb0427635d50d02263d6f535b12481
2025-05-08 08:05:44 +00:00
David
4d93187e58 Merge pull request #25354 from overleaf/dp-editor-redesign-modal
Update editor switcher modal contents

GitOrigin-RevId: 98772328004303c43ff3f9f0edbf8b0725041c60
2025-05-08 08:05:32 +00:00
David
efb66b4d2f Merge pull request #25327 from overleaf/dp-word-count
Add word count to file menu in new editor

GitOrigin-RevId: a5cb4d6cd37c46775056f696c0f19fcabd3f4131
2025-05-08 08:05:27 +00:00
Jakob Ackermann
e4156e19b8 [web] use raw compile timeout in compile-result-backend event (#25141)
The alias was broken following the 60s -> 20s compile timeout change.

GitOrigin-RevId: c2172090e17be60490adaae245a1f0b045e93cf1
2025-05-08 08:05:14 +00:00
Brian Gough
f9b36cd5be Merge pull request #25241 from overleaf/bg-remove-existing-chunk-buffer
remove existing chunk redis backend and chunk buffer

GitOrigin-RevId: 28fb02d1802312de6892e2fb7dd59191e3fc8914
2025-05-08 08:05:09 +00:00
Jakob Ackermann
5cc0895c56 [clsi] enable keepAlive on global HTTP agents (#25350)
GitOrigin-RevId: c9478b405ac32ca55aeb3bcf9f24052477464667
2025-05-07 08:08:10 +00:00
Antoine Clausse
07b37abcb3 [web] Improve FileTooLargeError handling in FileWriter.js (#25278)
* Improve FileTooLargeError handling in FileWriter.js

* handle errors on passThrough stream
* unlink files on error
* fail `writeUrlToDisk` if content-length header is too large

With Node 22, the test `Open In Overleaf - when POSTing a snip_uri for a file that is too large` fails.

I initially tried replacing it with a check of the `content-length` header. But then I managed to make the old test pass by adding a handler (`passThrough.on('error', ...)`)

* Unlink files asynchronously, add stream destroys on error

* Remove eslint disables

* Remove `stream.on('error', ...)` and `passThrough.on('error', ...)`

* Revert `Content-Length` check

* Re-add `stream.on('error', errorHandler)`; Remove it on 'response'

* Only report unlink errors there is an error(!!) that's not ENOENT

GitOrigin-RevId: fefe49519ec6f54df5eef69a2c2a75518f9d3748
2025-05-07 08:08:06 +00:00
Antoine Clausse
e7329b9660 [web] Remove script remove_emails_with_commas.mjs (#25356)
It ran in prod and updated 112 users

GitOrigin-RevId: 730f6544e7a5bb4d08095b48fb697b5c8e7a08be
2025-05-07 08:08:01 +00:00
Antoine Clausse
eddeca2942 [history-v1] Update config from 1.31.0 to 3.3.12 (#25077)
This removes some DeprecationWarnings in history-v1

The update should be safe:
```
  3.0.0 / 2018-11-20
  Ensure config array items and objects are sealed @fgheorghe
  This required a major version bump in case someone
  relied on the ability to mutate non-sealed data.

  2.0.0 / 2018-07-26
  Potential for backward incompatibility requiring a major version bump.

  Safe to upgrade to major version 2 if you're using a recent NodeJS version and you're not trying to mutate config arrays.

  Added array immutability - jacobemerick
  Removed Node V.4 support
```

https://github.com/node-config/node-config/blob/master/History.md

GitOrigin-RevId: 8384247d1ad2cd659703b4ba50edf7212076dcf3
2025-05-07 08:07:56 +00:00
M Fahru
661aa20c09 Merge pull request #25288 from overleaf/mf-stripe-webhook-subscription-updated
[web] Handle `customer.subscription.updated` stripe webhook event type

GitOrigin-RevId: 821baee5d5a45b92ee7bce47598a5e3ea5aa95ea
2025-05-07 08:07:44 +00:00
M Fahru
6c3cc794a4 Merge pull request #25161 from overleaf/mf-stripe-webhook
[web] Implement stripe webhook for `customer.subscription.created` event type

GitOrigin-RevId: f32e7607ddf900211efbe487bcd1f09172100178
2025-05-07 08:07:39 +00:00
Jessica Lawshe
12939b91b3 Merge pull request #25351 from overleaf/revert-24919-jel-create-group-audit-log
Revert "[web] Add group audit log"

GitOrigin-RevId: cf192bbe3ebdb693f18bab9c1c5d08da18ed34c0
2025-05-07 08:07:34 +00:00
Tim Down
f72a34f25b Merge pull request #25348 from overleaf/td-react-18-flaky-tests
Attempt to fix two flaky frontend project dashboard tests

GitOrigin-RevId: 1d5c3a05f7439ad3e22e5de96da8628ad8dd27c5
2025-05-07 08:07:29 +00:00
Jimmy Domagala-Tang
c060358cd8 Merge pull request #25223 from overleaf/jdt-dk-commons-toggle-annual-discount-bundle
Allow for commons to toggle annual for the AI Assist bundle

GitOrigin-RevId: 719dbb4944e3a447e03aa5c3fee7d0f5a0ce005b
2025-05-07 08:07:25 +00:00
Jimmy Domagala-Tang
f29bd47911 Merge pull request #25252 from overleaf/jdt-add-addon-to-cancellation-mssg-in-subs
Show Assist Add-on for pending and cancelled subscriptions

GitOrigin-RevId: df733d7078c231a5de989bc070b37e3c250fdb37
2025-05-07 08:07:20 +00:00
Jessica Lawshe
59275eeb84 Merge pull request #24919 from overleaf/jel-create-group-audit-log
[web] Add group audit log

GitOrigin-RevId: b59c38c57f555f18cdfa5dd697ad38d78b590996
2025-05-07 08:07:12 +00:00
Antoine Clausse
bc4c3c4ef8 [web] Promisify ClsiCookieManager and CompileController (reapply again) (#25280)
* Reapply "[web] Promisify ClsiCookieManager and CompileController (reapply and fix)"

This reverts commit 98cb9127ff2b7c7c347c560766f749265d712490.

* Fix: Use query parameters correctly (!!)

* Add unit test on `checkIsLoadSheddingEvent`

* Remove interference between tests: rename to `ClsiCookieManager2` when it's re-sandboxed

* Add test: 'should report "cycle" when other is UP'

GitOrigin-RevId: 3146b149954b908830226cb03b51d9adfa08ec2e
2025-05-07 08:07:07 +00:00
Antoine Clausse
e3dd47ba6e [web] Fix date format in emails.createdAt, use new Date() instead of Date.now() (#25322)
GitOrigin-RevId: c94700accb1df902926779c1e6321be63cf65235
2025-05-07 08:07:02 +00:00
Antoine Clausse
81941ff335 Update some dependencies so they're compatible with Node 22 (#25317)
* `"@google-cloud/profiler": "^6.0.3"`

* `bin/npm update pprof`

* `bin/npm update nan`

* `bin/npm update @google-cloud/profiler`

* Ignore false positive of `@typescript-eslint/return-await`

> Returning an awaited value that is not a promise is not allowed
Though the function was promisified

GitOrigin-RevId: 24dbe3e8df2b55c0b9583ac79a61e0956ac3fac0
2025-05-07 08:06:57 +00:00
Antoine Clausse
9a2847dbee [web] Add startup metrics (#25277)
* [web] refactor startup sequence

The primary objective here is to call loadGlobalBlobs() only once.
But to get there, we need to reorder things and add extra try/catch
sections to ensure we are not letting the global uncaughtException
handler catch startup errors.

Co-authored-by: Antoine Clausse <antoine.clausse@overleaf.com>

* [web] add metrics for startup steps

Co-authored-by: Antoine Clausse <antoine.clausse@overleaf.com>

---------

Co-authored-by: Jakob Ackermann <jakob.ackermann@overleaf.com>
GitOrigin-RevId: c73edea02516e919d55b896588dcd1862835fedf
2025-05-07 08:06:52 +00:00
Antoine Clausse
f0856c862f [web] Migrate two-factor-authentication module to BS5 (#25181)
* Delete unused file error.pug

* Revert-me: Enable 2FA locally

* Migrate 2FA pages to BS5

* Add BS5 notification classes to hydrate-form.js

* Revert "Revert-me: Enable 2FA locally"

This reverts commit 2874bedb05e579623e5beb6cf518aa8608808802.

* Fix: Re-add .text-capitalize on button

* Use `notification` mixin for success state

* Append complex notifications with icons in `showMessages`

* Keep the BS3 version of the notification in `showMessages`, move the BS5 implementation to `createNotificationFromMessageBS5`

Check the Boostrap version with `!window?.Frontend?.['bootstrap-3']`, which is a bit hacky

* Update breakpoings in 2FA form to leave more room for error notification

* Address PR comments:

* Remove useless `createTextNode`
* Use `isBootstrap5`
* `Setup` -> `Set Up`

GitOrigin-RevId: d7285853ea1191da7711b7bada8d65ff064bc27d
2025-05-07 08:06:48 +00:00
Jakob Ackermann
6881ba956a [clsi-cache] only use sharding from updated project editor tabs (#25326)
GitOrigin-RevId: 1754276bed3186c0536055c983e32476cc90d416
2025-05-07 08:06:39 +00:00
Alf Eaton
bfe42734bc Merge pull request #25261 from overleaf/ae-textlayer-layer
Move `will-change: transform` to textLayer

GitOrigin-RevId: 15fdd919da54ed95e115d664156066e6fda36982
2025-05-07 08:06:31 +00:00
Alf Eaton
c3368167d0 Remove z-index from outline elements (#25265)
GitOrigin-RevId: 39b85a478b71bf42ebb6b886b6ae1b4ed6557570
2025-05-07 08:06:26 +00:00
Jakob Ackermann
5ce1685b5b [clsi-cache] shard each zone into three instances (#25301)
* [clsi-cache] shard per zone into three instances

Keep the old instance as read fallback. We can remove it in 4 days.

Disk size: 2Ti gives us the maximum write throughput of 240MiB/s on a
N2D instance with fewer than 8 vCPUs.

* [clsi] fix format

* [k8s] clsi-cache: bring back storage-classes

* [k8s] clsi-cache: fix reference to zonal storage-classes

* [k8s] clsi-cache: add logging configs

* [clsi] improve sharding

Co-authored-by: Brian Gough <brian.gough@overleaf.com>

* [clsi] fix sharding

Index needs to be positive.

* [clsi] fix sharding

The random part is static per machine/process.

* [clsi] restrict clsi-cache to user projects

Co-authored-by: Brian Gough <brian.gough@overleaf.com>

* [k8s] clsi-cache: align CLSI_CACHE_NGINX_HOST with service LB

---------

Co-authored-by: Brian Gough <brian.gough@overleaf.com>
GitOrigin-RevId: 1efb1b3245c8194c305420b25e774ea735251fb3
2025-05-07 08:06:16 +00:00
Tim Down
aa97dbdbb6 Merge pull request #25269 from overleaf/td-flaky-tags-test
Add waits for flaky tag list test

GitOrigin-RevId: 9d0bf2acd54d07e96fe6837296176e62bf981947
2025-05-07 08:05:59 +00:00
David
42eb4b2779 Merge pull request #25320 from overleaf/dp-review-panel-shortcut
Fix open review panel shortcut in new editor

GitOrigin-RevId: 3e4b65ad1f1943574ba937460722912ff382bc39
2025-05-07 08:05:51 +00:00
David
0261d701a7 Merge pull request #25238 from overleaf/dp-tooltips
Add tooltip to new editor home button

GitOrigin-RevId: 91f47659caf64a7ee31ed156d4ee2d5c933e05b8
2025-05-07 08:05:46 +00:00
David
08c5b11689 Merge pull request #25248 from overleaf/dp-history-text-color
Add explicit color for history text

GitOrigin-RevId: 4b595ea824d75181c041d44fc48ea81fec864316
2025-05-07 08:05:41 +00:00
David
1cd8eba098 Merge pull request #25249 from overleaf/dp-chat-message-read
Mark messages as read when opening chat tab

GitOrigin-RevId: d0e3290cad72716cbbdf5b6cc92f6c1d387a92c7
2025-05-07 08:05:36 +00:00
Jakob Ackermann
07b2255426 [misc] cleanup .dockerignore and .gitignore files (#25312)
- Remove settings ignore, they are inconsistent and break local prettier
- Remove .dockerignore files, only root ignore file is used
- Move .idea/.run/*.swp/coverage to root
- Remove .npmrc entries, we are no longer writing the rc file
- Remove node_modules/.DS_Store, is contained in root
- Remove cruft

GitOrigin-RevId: 3025fd5acaef343312f55149466c638e759a6e1f
2025-05-07 08:05:24 +00:00
Jimmy Domagala-Tang
d95340edbc Merge pull request #25145 from overleaf/jdt-wf-premium-src
Add premium source to Writefull entitlement sync

GitOrigin-RevId: bbebd7741efdf40a444768255b4aade857aca602
2025-05-06 08:05:32 +00:00
Jakob Ackermann
a5e2708eae [document-updater] add safe rollback point for history-ot (#25283)
GitOrigin-RevId: d7230dd14a379a27d2c6ab03a006463a18979d06
2025-05-06 08:05:28 +00:00
M Fahru
c8a410d358 Merge pull request #25155 from overleaf/mf-use-stripe-v18
[web] Upgrade stripe to v18

GitOrigin-RevId: df522f73132e99e38f1716bf33e8ff4881bd5430
2025-05-06 08:05:19 +00:00
Domagoj Kriskovic
473f767465 Update event tracking for AI assist payment flow (#25222)
GitOrigin-RevId: feb7987b1397d70b3a04c797bd2db92e42c325f5
2025-05-06 08:04:56 +00:00
695 changed files with 15400 additions and 9919 deletions

View file

@ -1,6 +1,5 @@
volumes:
clsi-cache:
clsi-output:
filestore-public-files:
filestore-template-files:
filestore-uploads:
@ -33,9 +32,9 @@ services:
user: root
volumes:
- ${PWD}/compiles:/overleaf/services/clsi/compiles
- ${PWD}/output:/overleaf/services/clsi/output
- ${DOCKER_SOCKET_PATH:-/var/run/docker.sock}:/var/run/docker.sock
- clsi-cache:/overleaf/services/clsi/cache
- clsi-output:/overleaf/services/clsi/output
contacts:
build:

View file

@ -73,7 +73,11 @@ services:
## Server Pro ##
################
## Sandboxed Compiles: https://github.com/overleaf/overleaf/wiki/Server-Pro:-Sandboxed-Compiles
## The Community Edition is intended for use in environments where all users are trusted and is not appropriate for
## scenarios where isolation of users is required. Sandboxed Compiles are not available in the Community Edition,
## so the following environment variables must be commented out to avoid compile issues.
##
## Sandboxed Compiles: https://docs.overleaf.com/on-premises/configuration/overleaf-toolkit/server-pro-only-configuration/sandboxed-compiles
SANDBOXED_COMPILES: 'true'
### Bind-mount source for /var/lib/overleaf/data/compiles inside the container.
SANDBOXED_COMPILES_HOST_DIR_COMPILES: '/home/user/sharelatex_data/data/compiles'

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,46 +0,0 @@
compileFolder
Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# OS generated files #
######################
.DS_Store?
ehthumbs.db
Icon?
Thumbs.db
/node_modules/*
data/*/*
**.swp
/log.json
hash_folder
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ access-token-encryptor
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,3 +0,0 @@
# managed by monorepo$ bin/update_build_scripts
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ fetch-utils
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,3 +0,0 @@
node_modules
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ logger
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,3 +0,0 @@
node_modules
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ metrics
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -5,6 +5,8 @@
* before any other module to support code instrumentation.
*/
const metricsModuleImportStartTime = performance.now()
const APP_NAME = process.env.METRICS_APP_NAME || 'unknown'
const BUILD_VERSION = process.env.BUILD_VERSION
const ENABLE_PROFILE_AGENT = process.env.ENABLE_PROFILE_AGENT === 'true'
@ -103,3 +105,5 @@ function recordProcessStart() {
const metrics = require('.')
metrics.inc('process_startup')
}
module.exports = { metricsModuleImportStartTime }

View file

@ -9,7 +9,7 @@
"main": "index.js",
"dependencies": {
"@google-cloud/opentelemetry-cloud-trace-exporter": "^2.1.0",
"@google-cloud/profiler": "^6.0.0",
"@google-cloud/profiler": "^6.0.3",
"@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-node": "^0.39.1",
"@opentelemetry/exporter-trace-otlp-http": "^0.41.2",

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,3 +0,0 @@
# managed by monorepo$ bin/update_build_scripts
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ mongo-utils
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,5 +0,0 @@
.nyc_output
coverage
node_modules/
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ o-error
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -1,20 +1,34 @@
// @ts-check
/**
* Light-weight helpers for handling JavaScript Errors in node.js and the
* browser.
*/
class OError extends Error {
/**
* The error that is the underlying cause of this error
*
* @type {unknown}
*/
cause
/**
* List of errors encountered as the callback chain is unwound
*
* @type {TaggedError[] | undefined}
*/
_oErrorTags
/**
* @param {string} message as for built-in Error
* @param {Object} [info] extra data to attach to the error
* @param {Error} [cause] the internal error that caused this error
* @param {unknown} [cause] the internal error that caused this error
*/
constructor(message, info, cause) {
super(message)
this.name = this.constructor.name
if (info) this.info = info
if (cause) this.cause = cause
/** @private @type {Array<TaggedError> | undefined} */
this._oErrorTags // eslint-disable-line
}
/**
@ -31,7 +45,7 @@ class OError extends Error {
/**
* Wrap the given error, which caused this error.
*
* @param {Error} cause the internal error that caused this error
* @param {unknown} cause the internal error that caused this error
* @return {this}
*/
withCause(cause) {
@ -65,13 +79,16 @@ class OError extends Error {
* }
* }
*
* @param {Error} error the error to tag
* @template {unknown} E
* @param {E} error the error to tag
* @param {string} [message] message with which to tag `error`
* @param {Object} [info] extra data with wich to tag `error`
* @return {Error} the modified `error` argument
* @return {E} the modified `error` argument
*/
static tag(error, message, info) {
const oError = /** @type{OError} */ (error)
const oError = /** @type {{ _oErrorTags: TaggedError[] | undefined }} */ (
error
)
if (!oError._oErrorTags) oError._oErrorTags = []
@ -102,7 +119,7 @@ class OError extends Error {
*
* If an info property is repeated, the last one wins.
*
* @param {Error | null | undefined} error any error (may or may not be an `OError`)
* @param {unknown} error any error (may or may not be an `OError`)
* @return {Object}
*/
static getFullInfo(error) {
@ -129,7 +146,7 @@ class OError extends Error {
* Return the `stack` property from `error`, including the `stack`s for any
* tagged errors added with `OError.tag` and for any `cause`s.
*
* @param {Error | null | undefined} error any error (may or may not be an `OError`)
* @param {unknown} error any error (may or may not be an `OError`)
* @return {string}
*/
static getFullStack(error) {
@ -143,7 +160,7 @@ class OError extends Error {
stack += `\n${oError._oErrorTags.map(tag => tag.stack).join('\n')}`
}
const causeStack = oError.cause && OError.getFullStack(oError.cause)
const causeStack = OError.getFullStack(oError.cause)
if (causeStack) {
stack += '\ncaused by:\n' + indent(causeStack)
}

View file

@ -268,6 +268,11 @@ describe('utils', function () {
expect(OError.getFullInfo(null)).to.deep.equal({})
})
it('works when given a string', function () {
const err = 'not an error instance'
expect(OError.getFullInfo(err)).to.deep.equal({})
})
it('works on a normal error', function () {
const err = new Error('foo')
expect(OError.getFullInfo(err)).to.deep.equal({})

View file

@ -35,6 +35,14 @@ describe('OError', function () {
expect(err2.cause.message).to.equal('cause 2')
})
it('accepts non-Error causes', function () {
const err1 = new OError('foo', {}, 'not-an-error')
expect(err1.cause).to.equal('not-an-error')
const err2 = new OError('foo').withCause('not-an-error')
expect(err2.cause).to.equal('not-an-error')
})
it('handles a custom error type with a cause', function () {
function doSomethingBadInternally() {
throw new Error('internal error')

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,4 +0,0 @@
/node_modules
*.swp
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ object-persistor
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -305,8 +305,10 @@ module.exports = class FSPersistor extends AbstractPersistor {
async _listDirectory(path) {
if (this.useSubdirectories) {
// eslint-disable-next-line @typescript-eslint/return-await
return await glob(Path.join(path, '**'))
} else {
// eslint-disable-next-line @typescript-eslint/return-await
return await glob(`${path}_*`)
}
}

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,5 +0,0 @@
/coverage
/node_modules
# managed by monorepo$ bin/update_build_scripts
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ overleaf-editor-core
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -18,6 +18,7 @@ const MoveFileOperation = require('./lib/operation/move_file_operation')
const SetCommentStateOperation = require('./lib/operation/set_comment_state_operation')
const EditFileOperation = require('./lib/operation/edit_file_operation')
const EditNoOperation = require('./lib/operation/edit_no_operation')
const EditOperationTransformer = require('./lib/operation/edit_operation_transformer')
const SetFileMetadataOperation = require('./lib/operation/set_file_metadata_operation')
const NoOperation = require('./lib/operation/no_operation')
const Operation = require('./lib/operation')
@ -43,6 +44,8 @@ const TrackingProps = require('./lib/file_data/tracking_props')
const Range = require('./lib/range')
const CommentList = require('./lib/file_data/comment_list')
const LazyStringFileData = require('./lib/file_data/lazy_string_file_data')
const StringFileData = require('./lib/file_data/string_file_data')
const EditOperationBuilder = require('./lib/operation/edit_operation_builder')
exports.AddCommentOperation = AddCommentOperation
exports.Author = Author
@ -58,6 +61,7 @@ exports.DeleteCommentOperation = DeleteCommentOperation
exports.File = File
exports.FileMap = FileMap
exports.LazyStringFileData = LazyStringFileData
exports.StringFileData = StringFileData
exports.History = History
exports.Label = Label
exports.AddFileOperation = AddFileOperation
@ -65,6 +69,8 @@ exports.MoveFileOperation = MoveFileOperation
exports.SetCommentStateOperation = SetCommentStateOperation
exports.EditFileOperation = EditFileOperation
exports.EditNoOperation = EditNoOperation
exports.EditOperationBuilder = EditOperationBuilder
exports.EditOperationTransformer = EditOperationTransformer
exports.SetFileMetadataOperation = SetFileMetadataOperation
exports.NoOperation = NoOperation
exports.Operation = Operation

View file

@ -13,7 +13,7 @@ const V2DocVersions = require('./v2_doc_versions')
/**
* @import Author from "./author"
* @import { BlobStore } from "./types"
* @import { BlobStore, RawChange } from "./types"
*/
/**
@ -54,7 +54,7 @@ class Change {
/**
* For serialization.
*
* @return {Object}
* @return {RawChange}
*/
toRaw() {
function toRaw(object) {

View file

@ -88,6 +88,14 @@ class StringFileData extends FileData {
return content
}
/**
* Return docstore view of a doc: each line separated
* @return {string[]}
*/
getLines() {
return this.getContent({ filterTrackedDeletes: true }).split('\n')
}
/** @inheritdoc */
getByteLength() {
return Buffer.byteLength(this.content)

View file

@ -36,6 +36,20 @@ class EditOperationBuilder {
}
throw new Error('Unsupported operation in EditOperationBuilder.fromJSON')
}
/**
* @param {unknown} raw
* @return {raw is RawEditOperation}
*/
static isValid(raw) {
return (
isTextOperation(raw) ||
isRawAddCommentOperation(raw) ||
isRawDeleteCommentOperation(raw) ||
isRawSetCommentStateOperation(raw) ||
isRawEditNoOperation(raw)
)
}
}
/**

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,3 +0,0 @@
# managed by monorepo$ bin/update_build_scripts
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ promise-utils
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,13 +0,0 @@
**.swp
app.js
app/js/
test/unit/js/
public/build/
node_modules/
/public/js/chat.js
plato/
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ ranges-tracker
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,13 +0,0 @@
**.swp
app.js
app/js/
test/unit/js/
public/build/
node_modules/
/public/js/chat.js
plato/
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -97,7 +97,8 @@ module.exports = class RedisLocker {
}
/**
* @param {Callback} callback
* @param {string} id
* @param {function(Error, boolean, string): void} callback
*/
tryLock(id, callback) {
if (callback == null) {
@ -106,7 +107,7 @@ module.exports = class RedisLocker {
const lockValue = this.randomLock()
const key = this.getKey(id)
const startTime = Date.now()
return this.rclient.set(
this.rclient.set(
key,
lockValue,
'EX',
@ -121,7 +122,7 @@ module.exports = class RedisLocker {
const timeTaken = Date.now() - startTime
if (timeTaken > MAX_REDIS_REQUEST_LENGTH) {
// took too long, so try to free the lock
return this.releaseLock(id, lockValue, function (err, result) {
this.releaseLock(id, lockValue, function (err, result) {
if (err != null) {
return callback(err)
} // error freeing lock
@ -139,7 +140,8 @@ module.exports = class RedisLocker {
}
/**
* @param {Callback} callback
* @param {string} id
* @param {function(Error, string): void} callback
*/
getLock(id, callback) {
if (callback == null) {
@ -153,7 +155,7 @@ module.exports = class RedisLocker {
return callback(e)
}
return this.tryLock(id, (error, gotLock, lockValue) => {
this.tryLock(id, (error, gotLock, lockValue) => {
if (error != null) {
return callback(error)
}
@ -173,14 +175,15 @@ module.exports = class RedisLocker {
}
/**
* @param {Callback} callback
* @param {string} id
* @param {function(Error, boolean): void} callback
*/
checkLock(id, callback) {
if (callback == null) {
callback = function () {}
}
const key = this.getKey(id)
return this.rclient.exists(key, (err, exists) => {
this.rclient.exists(key, (err, exists) => {
if (err != null) {
return callback(err)
}
@ -196,30 +199,26 @@ module.exports = class RedisLocker {
}
/**
* @param {Callback} callback
* @param {string} id
* @param {string} lockValue
* @param {function(Error, boolean): void} callback
*/
releaseLock(id, lockValue, callback) {
const key = this.getKey(id)
return this.rclient.eval(
UNLOCK_SCRIPT,
1,
key,
lockValue,
(err, result) => {
if (err != null) {
return callback(err)
} else if (result != null && result !== 1) {
// successful unlock should release exactly one key
logger.error(
{ id, key, lockValue, redis_err: err, redis_result: result },
'unlocking error'
)
metrics.inc(this.metricsPrefix + '-unlock-error')
return callback(new Error('tried to release timed out lock'))
} else {
return callback(null, result)
}
this.rclient.eval(UNLOCK_SCRIPT, 1, key, lockValue, (err, result) => {
if (err != null) {
return callback(err)
} else if (result != null && result !== 1) {
// successful unlock should release exactly one key
logger.error(
{ id, key, lockValue, redis_err: err, redis_result: result },
'unlocking error'
)
metrics.inc(this.metricsPrefix + '-unlock-error')
return callback(new Error('tried to release timed out lock'))
} else {
return callback(null, result)
}
)
})
}
}

View file

@ -5,6 +5,6 @@ redis-wrapper
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,5 +0,0 @@
/.npmrc
/node_modules
# managed by monorepo$ bin/update_build_scripts
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ settings
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,3 +0,0 @@
# managed by monorepo$ bin/update_build_scripts
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -5,6 +5,6 @@ stream-utils
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

1662
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -37,7 +37,7 @@
},
"swagger-tools": {
"body-parser": "1.20.3",
"multer": "1.4.5-lts.1",
"multer": "2.0.0",
"path-to-regexp": "3.3.0",
"qs": "6.13.0"
}

View file

@ -2,7 +2,7 @@
# Overleaf Base Image (sharelatex/sharelatex-base)
# --------------------------------------------------
FROM phusion/baseimage:noble-1.0.0
FROM phusion/baseimage:noble-1.0.2
# Makes sure LuaTex cache is writable
# -----------------------------------
@ -10,7 +10,7 @@ ENV TEXMFVAR=/var/lib/overleaf/tmp/texmf-var
# Update to ensure dependencies are updated
# ------------------------------------------
ENV REBUILT_AFTER="2025-03-27"
ENV REBUILT_AFTER="2025-05-19"
# Install dependencies
# --------------------
@ -30,7 +30,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
# install Node.js https://github.com/nodesource/distributions#nodejs
&& mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \
&& apt-get update \
&& apt-get install -y nodejs \
\

View file

@ -1,3 +1,4 @@
*/20 * * * * root /overleaf/cron/project-history-periodic-flush.sh >> /var/log/overleaf/cron-project-history-periodic-flush.log 2>&1
30 * * * * root /overleaf/cron/project-history-retry-soft.sh >> /var/log/overleaf/project-history-retry-soft.log 2>&1
45 * * * * root /overleaf/cron/project-history-retry-hard.sh >> /var/log/overleaf/project-history-retry-hard.log 2>&1
0 3 * * * root /overleaf/cron/project-history-flush-all.sh >> /var/log/overleaf/project-history-flush-all.log 2>&1

View file

@ -79,6 +79,7 @@ const settings = {
host: process.env.OVERLEAF_REDIS_HOST || 'dockerhost',
port: process.env.OVERLEAF_REDIS_PORT || '6379',
password: process.env.OVERLEAF_REDIS_PASS || undefined,
tls: process.env.OVERLEAF_REDIS_TLS === 'true' ? {} : undefined,
key_schema: {
// document-updater
blockingKey({ doc_id }) {

View file

@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -eux
echo "---------------------------------"
echo "Flush all project-history changes"
echo "---------------------------------"
date
source /etc/container_environment.sh
source /etc/overleaf/env.sh
cd /overleaf/services/project-history && node scripts/flush_all.js
echo "Done flushing all project-history changes"

View file

@ -0,0 +1,14 @@
FROM sharelatex/sharelatex:5.4.0
RUN apt update && apt install -y linux-libc-dev \
&& unattended-upgrade --verbose --no-minimal-upgrade-steps \
&& rm -rf /var/lib/apt/lists/*
COPY package-lock.json.diff .
RUN patch package-lock.json < package-lock.json.diff
RUN npm install --omit=dev
# fix tls configuration in redis
COPY issue_24996.patch .
RUN patch -p0 /etc/overleaf/settings.js < issue_24996.patch \
&& rm issue_24996.patch

View file

@ -0,0 +1,10 @@
--- settings.js
+++ settings.js
@@ -79,6 +79,7 @@ const settings = {
host: process.env.OVERLEAF_REDIS_HOST || 'dockerhost',
port: process.env.OVERLEAF_REDIS_PORT || '6379',
password: process.env.OVERLEAF_REDIS_PASS || undefined,
+ tls: process.env.OVERLEAF_REDIS_TLS === 'true' ? {} : undefined,
key_schema: {
// document-updater
blockingKey({ doc_id }) {

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
FROM node:20.18.2
FROM node:22.15.1
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - \
&& echo \
"deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \

View file

@ -294,7 +294,7 @@ describe('admin panel', function () {
cy.log('navigate to thrashed projects and delete the project')
cy.get('.project-list-sidebar-scroll').within(() => {
cy.findByText('Trashed Projects').click()
cy.findByText('Trashed projects').click()
})
findProjectRow(deletedProjectName).within(() =>
cy.findByRole('button', { name: 'Delete' }).click()
@ -319,7 +319,7 @@ describe('admin panel', function () {
login(user1)
cy.visit('/project')
cy.get('.project-list-sidebar-scroll').within(() => {
cy.findByText('Trashed Projects').click()
cy.findByText('Trashed projects').click()
})
cy.findByText(`${deletedProjectName} (Restored)`)
})

View file

@ -51,7 +51,7 @@ describe('Project creation and compilation', function () {
login('user@example.com')
createProject(sourceProjectName, {
type: 'Example Project',
type: 'Example project',
open: false,
}).as('sourceProjectId')
createProject(targetProjectName)
@ -79,7 +79,7 @@ describe('Project creation and compilation', function () {
const targetProjectName = `${sourceProjectName}-target`
login('user@example.com')
createProject(sourceProjectName, {
type: 'Example Project',
type: 'Example project',
open: false,
}).as('sourceProjectId')
createProject(targetProjectName).as('targetProjectId')

View file

@ -1,11 +1,7 @@
import {
createNewFile,
createProject,
enableLinkSharing,
openFile,
openProjectById,
openProjectViaLinkSharingAsUser,
toggleTrackChanges,
} from './helpers/project'
import { isExcludedBySharding, startWith } from './helpers/config'
import { ensureUserExists, login } from './helpers/login'
@ -26,7 +22,7 @@ describe('editor', () => {
beforeWithReRunOnTestRetry(function () {
projectName = `project-${uuid()}`
login('user@example.com')
createProject(projectName, { type: 'Example Project', open: false }).then(
createProject(projectName, { type: 'Example project', open: false }).then(
id => (projectId = id)
)
;({ recompile, waitForCompileRateLimitCoolOff } =
@ -66,12 +62,12 @@ describe('editor', () => {
cy.log('add word to dictionary')
cy.get('.ol-cm-spelling-error').contains(word).rightclick()
cy.findByText('Add to Dictionary').click()
cy.findByText('Add to dictionary').click()
cy.get('.ol-cm-spelling-error').should('not.exist')
cy.log('remove word from dictionary')
cy.get('button').contains('Menu').click()
cy.get('button').contains('Edit').click()
cy.get('button#dictionary-settings').contains('Edit').click()
cy.get('[id="dictionary-modal"]').within(() => {
cy.findByText(word)
.parent()
@ -92,136 +88,6 @@ describe('editor', () => {
})
})
describe('collaboration', () => {
beforeWithReRunOnTestRetry(function () {
enableLinkSharing().then(({ linkSharingReadAndWrite }) => {
const email = 'collaborator@example.com'
login(email)
openProjectViaLinkSharingAsUser(
linkSharingReadAndWrite,
projectName,
email
)
})
login('user@example.com')
waitForCompileRateLimitCoolOff(() => {
openProjectById(projectId)
})
})
it('track-changes', () => {
cy.log('disable track-changes before populating doc')
toggleTrackChanges(false)
const fileName = createNewFile()
const oldContent = 'oldContent'
cy.get('.cm-line').type(`${oldContent}\n\nstatic`)
cy.log('recompile to force flush')
recompile()
cy.log('enable track-changes for everyone')
toggleTrackChanges(true)
login('collaborator@example.com')
waitForCompileRateLimitCoolOff(() => {
openProjectById(projectId)
})
openFile(fileName, 'static')
cy.log('make changes in main file')
// cy.type() "clicks" in the center of the selected element before typing. This "click" discards the text as selected by the dblclick.
// Go down to the lower level event based typing, the frontend tests in web use similar events.
cy.get('.cm-editor').as('editor')
cy.get('@editor').findByText(oldContent).dblclick()
cy.get('@editor').trigger('keydown', { key: 'Delete' })
cy.get('@editor').trigger('keydown', { key: 'Enter' })
cy.get('@editor').trigger('keydown', { key: 'Enter' })
cy.log('recompile to force flush')
recompile()
login('user@example.com')
waitForCompileRateLimitCoolOff(() => {
openProjectById(projectId)
})
openFile(fileName, 'static')
cy.log('reject changes')
cy.contains('.toolbar-item', 'Review').click()
cy.get('.cm-content').should('not.contain.text', oldContent)
cy.findByText('Reject change').click({ force: true })
cy.contains('.toolbar-item', 'Review').click()
cy.log('recompile to force flush')
recompile()
cy.log('verify the changes are applied')
cy.get('.cm-content').should('contain.text', oldContent)
cy.log('disable track-changes for everyone again')
toggleTrackChanges(false)
})
it('track-changes rich text', () => {
cy.log('disable track-changes before populating doc')
toggleTrackChanges(false)
const fileName = createNewFile()
const oldContent = 'oldContent'
cy.get('.cm-line').type(`\\section{{}${oldContent}}\n\nstatic`)
cy.log('recompile to force flush')
recompile()
cy.log('enable track-changes for everyone')
toggleTrackChanges(true)
login('collaborator@example.com')
waitForCompileRateLimitCoolOff(() => {
openProjectById(projectId)
})
cy.log('enable visual editor and make changes in main file')
cy.findByText('Visual Editor').click()
openFile(fileName, 'static')
// cy.type() "clicks" in the center of the selected element before typing. This "click" discards the text as selected by the dblclick.
// Go down to the lower level event based typing, the frontend tests in web use similar events.
cy.get('.cm-editor').as('editor')
cy.get('@editor').findByText(oldContent).dblclick()
cy.get('@editor').trigger('keydown', { key: 'Delete' })
cy.get('@editor').trigger('keydown', { key: 'Enter' })
cy.get('@editor').trigger('keydown', { key: 'Enter' })
cy.log('recompile to force flush')
recompile()
login('user@example.com')
waitForCompileRateLimitCoolOff(() => {
openProjectById(projectId)
})
openFile(fileName, 'static')
cy.log('reject changes')
cy.contains('.toolbar-item', 'Review').click()
cy.get('.cm-content').should('not.contain.text', oldContent)
cy.findAllByText('Reject change').first().click({ force: true })
cy.contains('.toolbar-item', 'Review').click()
cy.log('recompile to force flush')
recompile()
cy.log('verify the changes are applied in the visual editor')
cy.findByText('Visual Editor').click()
cy.get('.cm-content').should('contain.text', oldContent)
cy.log('disable track-changes for everyone again')
toggleTrackChanges(false)
})
})
describe('editor', () => {
it('renders jpg', () => {
cy.findByTestId('file-tree').findByText('frog.jpg').click()

View file

@ -46,7 +46,7 @@ describe('git-bridge', function () {
function maybeClearAllTokens() {
cy.visit('/user/settings')
cy.findByText('Git Integration')
cy.findByText('Git integration')
cy.get('button')
.contains(/Generate token|Add another token/)
.then(btn => {
@ -63,7 +63,7 @@ describe('git-bridge', function () {
it('should render the git-bridge UI in the settings', () => {
maybeClearAllTokens()
cy.visit('/user/settings')
cy.findByText('Git Integration')
cy.findByText('Git integration')
cy.get('button').contains('Generate token').click()
cy.get('code')
.contains(/olp_[a-zA-Z0-9]{16}/)
@ -93,7 +93,7 @@ describe('git-bridge', function () {
cy.get('code').contains(`git clone ${gitURL(id.toString())}`)
})
cy.findByRole('button', {
name: 'Generate token',
name: /generate token/i,
}).click()
cy.get('code').contains(/olp_[a-zA-Z0-9]{16}/)
})
@ -107,7 +107,7 @@ describe('git-bridge', function () {
cy.get('code').contains(`git clone ${gitURL(id.toString())}`)
})
cy.findByText('Generate token').should('not.exist')
cy.findByText(/generate a new one in Account Settings/)
cy.findByText(/generate a new one in Account settings/i)
cy.findByText('Go to settings')
.should('have.attr', 'target', '_blank')
.and('have.attr', 'href', '/user/settings')
@ -196,7 +196,7 @@ describe('git-bridge', function () {
cy.get('code').contains(`git clone ${gitURL(projectId.toString())}`)
})
cy.findByRole('button', {
name: 'Generate token',
name: /generate token/i,
}).click()
cy.get('code')
.contains(/olp_[a-zA-Z0-9]{16}/)
@ -365,7 +365,7 @@ Hello world
it('should not render the git-bridge UI in the settings', () => {
login('user@example.com')
cy.visit('/user/settings')
cy.findByText('Git Integration').should('not.exist')
cy.findByText('Git integration').should('not.exist')
})
it('should not render the git-bridge UI in the editor', function () {
login('user@example.com')

View file

@ -5,11 +5,11 @@ import { v4 as uuid } from 'uuid'
export function createProject(
name: string,
{
type = 'Blank Project',
type = 'Blank project',
newProjectButtonMatcher = /new project/i,
open = true,
}: {
type?: 'Blank Project' | 'Example Project'
type?: 'Blank project' | 'Example project'
newProjectButtonMatcher?: RegExp
open?: boolean
} = {}
@ -37,7 +37,7 @@ export function createProject(
}
cy.findAllByRole('button').contains(newProjectButtonMatcher).click()
// FIXME: This should only look in the left menu
cy.findAllByText(type).first().click()
cy.findAllByText(new RegExp(type, 'i')).first().click()
cy.findByRole('dialog').within(() => {
cy.get('input').type(name)
cy.findByText('Create').click()
@ -215,37 +215,3 @@ export function createNewFile() {
return fileName
}
export function toggleTrackChanges(state: boolean) {
cy.findByText('Review').click()
cy.get('.track-changes-menu-button').then(el => {
// when the menu is expanded renders the `expand_more` icon,
// and the `chevron_right` icon when it's collapsed
if (!el.text().includes('expand_more')) {
el.click()
}
})
cy.findByText('Everyone')
.parent()
.within(() => {
cy.get('.form-check-input').then(el => {
if (el.prop('checked') === state) return
const id = uuid()
const alias = `@${id}`
cy.intercept({
method: 'POST',
url: '**/track_changes',
times: 1,
}).as(id)
if (state) {
cy.get('.form-check-input').check()
} else {
cy.get('.form-check-input').uncheck()
}
cy.wait(alias)
})
})
cy.contains('.toolbar-item', 'Review').click()
}

View file

@ -32,7 +32,7 @@ describe('Project List', () => {
before(() => {
login(REGULAR_USER)
createProject(projectName, { type: 'Example Project', open: false })
createProject(projectName, { type: 'Example project', open: false })
})
beforeEach(function () {
login(REGULAR_USER)

View file

@ -59,7 +59,9 @@ describe('SandboxedCompiles', function () {
})
function checkSyncTeX() {
describe('SyncTeX', function () {
// TODO(25342): re-enable
// eslint-disable-next-line mocha/no-skipped-tests
describe.skip('SyncTeX', function () {
let projectName: string
beforeEach(function () {
projectName = `Project ${uuid()}`

View file

@ -47,7 +47,9 @@ describe('Templates', () => {
cy.url().should('match', /\/templates$/)
})
it('should have templates feature', () => {
// TODO(25342): re-enable
// eslint-disable-next-line mocha/no-skipped-tests
it.skip('should have templates feature', () => {
login(TEMPLATES_USER)
const name = `Template ${Date.now()}`
const description = `Template Description ${Date.now()}`

View file

@ -1,12 +0,0 @@
**.swp
public/build/
node_modules/
plato/
**/*.map
# managed by dev-environment$ bin/update_build_scripts
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -2,7 +2,7 @@
# Instead run bin/update_build_scripts from
# https://github.com/overleaf/internal/
FROM node:20.18.2 AS base
FROM node:22.15.1 AS base
WORKDIR /overleaf/services/chat

View file

@ -32,12 +32,12 @@ HERE=$(shell pwd)
MONOREPO=$(shell cd ../../ && pwd)
# Run the linting commands in the scope of the monorepo.
# Eslint and prettier (plus some configs) are on the root.
RUN_LINTING = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(HERE) node:20.18.2 npm run --silent
RUN_LINTING = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(HERE) node:22.15.1 npm run --silent
RUN_LINTING_CI = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/.eslintignore:/overleaf/.eslintignore --volume $(MONOREPO)/.eslintrc:/overleaf/.eslintrc --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc:/overleaf/.prettierrc --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json ci/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER) npm run --silent
# Same but from the top of the monorepo
RUN_LINTING_MONOREPO = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(MONOREPO) node:20.18.2 npm run --silent
RUN_LINTING_MONOREPO = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(MONOREPO) node:22.15.1 npm run --silent
SHELLCHECK_OPTS = \
--shell=bash \

View file

@ -4,6 +4,6 @@ chat
--env-add=
--env-pass-through=
--esmock-loader=False
--node-version=20.18.2
--node-version=22.15.1
--public-repo=False
--script-version=4.7.0

View file

@ -39,7 +39,7 @@ services:
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
user: root
mongo:
image: mongo:6.0.13
image: mongo:7.0.20
command: --replSet overleaf
volumes:
- ../../bin/shared/mongodb-init-replica-set.js:/docker-entrypoint-initdb.d/mongodb-init-replica-set.js

View file

@ -6,7 +6,7 @@ version: "2.3"
services:
test_unit:
image: node:20.18.2
image: node:22.15.1
volumes:
- .:/overleaf/services/chat
- ../../node_modules:/overleaf/node_modules
@ -21,7 +21,7 @@ services:
user: node
test_acceptance:
image: node:20.18.2
image: node:22.15.1
volumes:
- .:/overleaf/services/chat
- ../../node_modules:/overleaf/node_modules
@ -42,7 +42,7 @@ services:
command: npm run --silent test:acceptance
mongo:
image: mongo:6.0.13
image: mongo:7.0.20
command: --replSet overleaf
volumes:
- ../../bin/shared/mongodb-init-replica-set.js:/docker-entrypoint-initdb.d/mongodb-init-replica-set.js

View file

@ -1,14 +1,3 @@
**.swp
node_modules
test/acceptance/fixtures/tmp
compiles
output
.DS_Store
*~
cache
.vagrant
config/*
npm-debug.log
# managed by dev-environment$ bin/update_build_scripts
.npmrc

View file

@ -1 +1 @@
20.18.2
22.15.1

View file

@ -2,7 +2,7 @@
# Instead run bin/update_build_scripts from
# https://github.com/overleaf/internal/
FROM node:20.18.2 AS base
FROM node:22.15.1 AS base
WORKDIR /overleaf/services/clsi
COPY services/clsi/install_deps.sh /overleaf/services/clsi/

View file

@ -24,7 +24,6 @@ DOCKER_COMPOSE_TEST_UNIT = \
clean:
-docker rmi ci/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER)
-docker rmi gcr.io/overleaf-ops/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER)
-docker rmi us-east1-docker.pkg.dev/overleaf-ops/ol-docker/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER)
-$(DOCKER_COMPOSE_TEST_UNIT) down --rmi local
-$(DOCKER_COMPOSE_TEST_ACCEPTANCE) down --rmi local
@ -33,12 +32,12 @@ HERE=$(shell pwd)
MONOREPO=$(shell cd ../../ && pwd)
# Run the linting commands in the scope of the monorepo.
# Eslint and prettier (plus some configs) are on the root.
RUN_LINTING = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(HERE) node:20.18.2 npm run --silent
RUN_LINTING = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(HERE) node:22.15.1 npm run --silent
RUN_LINTING_CI = docker run --rm --volume $(MONOREPO)/.editorconfig:/overleaf/.editorconfig --volume $(MONOREPO)/.eslintignore:/overleaf/.eslintignore --volume $(MONOREPO)/.eslintrc:/overleaf/.eslintrc --volume $(MONOREPO)/.prettierignore:/overleaf/.prettierignore --volume $(MONOREPO)/.prettierrc:/overleaf/.prettierrc --volume $(MONOREPO)/tsconfig.backend.json:/overleaf/tsconfig.backend.json ci/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER) npm run --silent
# Same but from the top of the monorepo
RUN_LINTING_MONOREPO = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(MONOREPO) node:20.18.2 npm run --silent
RUN_LINTING_MONOREPO = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(MONOREPO) node:22.15.1 npm run --silent
SHELLCHECK_OPTS = \
--shell=bash \
@ -129,11 +128,10 @@ build:
--pull \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--tag ci/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER) \
--tag gcr.io/overleaf-ops/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER) \
--tag gcr.io/overleaf-ops/$(PROJECT_NAME):$(BRANCH_NAME) \
--cache-from gcr.io/overleaf-ops/$(PROJECT_NAME):$(BRANCH_NAME) \
--cache-from gcr.io/overleaf-ops/$(PROJECT_NAME):main \
--tag us-east1-docker.pkg.dev/overleaf-ops/ol-docker/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER) \
--tag us-east1-docker.pkg.dev/overleaf-ops/ol-docker/$(PROJECT_NAME):$(BRANCH_NAME) \
--cache-from us-east1-docker.pkg.dev/overleaf-ops/ol-docker/$(PROJECT_NAME):$(BRANCH_NAME) \
--cache-from us-east1-docker.pkg.dev/overleaf-ops/ol-docker/$(PROJECT_NAME):main \
--file Dockerfile \
../..

View file

@ -249,6 +249,9 @@ app.get('/health_check', function (req, res) {
if (Settings.processTooOld) {
return res.status(500).json({ processTooOld: true })
}
if (ProjectPersistenceManager.isAnyDiskCriticalLow()) {
return res.status(500).json({ diskCritical: true })
}
smokeTest.sendLastResult(res)
})
@ -296,9 +299,14 @@ const loadTcpServer = net.createServer(function (socket) {
}
const freeLoad = availableWorkingCpus - currentLoad
const freeLoadPercentage = Math.round(
(freeLoad / availableWorkingCpus) * 100
)
let freeLoadPercentage = Math.round((freeLoad / availableWorkingCpus) * 100)
if (ProjectPersistenceManager.isAnyDiskCriticalLow()) {
freeLoadPercentage = 0
}
if (ProjectPersistenceManager.isAnyDiskLow()) {
freeLoadPercentage = freeLoadPercentage / 2
}
if (
Settings.internal.load_balancer_agent.allow_maintenance &&
freeLoadPercentage <= 0

View file

@ -20,6 +20,19 @@ const TIMING_BUCKETS = [
0, 10, 100, 1000, 2000, 5000, 10000, 15000, 20000, 30000,
]
const MAX_ENTRIES_IN_OUTPUT_TAR = 100
const OBJECT_ID_REGEX = /^[0-9a-f]{24}$/
/**
* @param {string} projectId
* @return {{shard: string, url: string}}
*/
function getShard(projectId) {
// [timestamp 4bytes][random per machine 5bytes][counter 3bytes]
// [32bit 4bytes]
const last4Bytes = Buffer.from(projectId, 'hex').subarray(8, 12)
const idx = last4Bytes.readUInt32BE() % Settings.apis.clsiCache.shards.length
return Settings.apis.clsiCache.shards[idx]
}
/**
* @param {string} projectId
@ -29,6 +42,7 @@ const MAX_ENTRIES_IN_OUTPUT_TAR = 100
* @param {[{path: string}]} outputFiles
* @param {string} compileGroup
* @param {Record<string, any>} options
* @return {string | undefined}
*/
function notifyCLSICacheAboutBuild({
projectId,
@ -39,14 +53,16 @@ function notifyCLSICacheAboutBuild({
compileGroup,
options,
}) {
if (!Settings.apis.clsiCache.enabled) return
if (!Settings.apis.clsiCache.enabled) return undefined
if (!OBJECT_ID_REGEX.test(projectId)) return undefined
const { url, shard } = getShard(projectId)
/**
* @param {[{path: string}]} files
*/
const enqueue = files => {
Metrics.count('clsi_cache_enqueue_files', files.length)
fetchNothing(`${Settings.apis.clsiCache.url}/enqueue`, {
fetchNothing(`${url}/enqueue`, {
method: 'POST',
json: {
projectId,
@ -97,6 +113,8 @@ function notifyCLSICacheAboutBuild({
'build output.tar.gz for clsi cache failed'
)
})
return shard
}
/**
@ -155,6 +173,7 @@ async function downloadOutputDotSynctexFromCompileCache(
outputDir
) {
if (!Settings.apis.clsiCache.enabled) return false
if (!OBJECT_ID_REGEX.test(projectId)) return false
const timer = new Metrics.Timer(
'clsi_cache_download',
@ -165,7 +184,7 @@ async function downloadOutputDotSynctexFromCompileCache(
let stream
try {
stream = await fetchStream(
`${Settings.apis.clsiCache.url}/project/${projectId}/${
`${getShard(projectId).url}/project/${projectId}/${
userId ? `user/${userId}/` : ''
}build/${editorId}-${buildId}/search/output/output.synctex.gz`,
{
@ -205,8 +224,9 @@ async function downloadOutputDotSynctexFromCompileCache(
*/
async function downloadLatestCompileCache(projectId, userId, compileDir) {
if (!Settings.apis.clsiCache.enabled) return false
if (!OBJECT_ID_REGEX.test(projectId)) return false
const url = `${Settings.apis.clsiCache.url}/project/${projectId}/${
const url = `${getShard(projectId).url}/project/${projectId}/${
userId ? `user/${userId}/` : ''
}latest/output/output.tar.gz`
const timer = new Metrics.Timer(

View file

@ -112,12 +112,13 @@ function compile(req, res, next) {
buildId = error.buildId
}
let clsiCacheShard
if (
status === 'success' &&
request.editorId &&
request.populateClsiCache
) {
notifyCLSICacheAboutBuild({
clsiCacheShard = notifyCLSICacheAboutBuild({
projectId: request.project_id,
userId: request.user_id,
buildId: outputFiles[0].build,
@ -144,6 +145,7 @@ function compile(req, res, next) {
stats,
timings,
buildId,
clsiCacheShard,
outputUrlPrefix: Settings.apis.clsi.outputUrlPrefix,
outputFiles: outputFiles.map(file => ({
url:
@ -188,7 +190,8 @@ function clearCache(req, res, next) {
}
function syncFromCode(req, res, next) {
const { file, editorId, buildId, compileFromClsiCache } = req.query
const { file, editorId, buildId } = req.query
const compileFromClsiCache = req.query.compileFromClsiCache === 'true'
const line = parseInt(req.query.line, 10)
const column = parseInt(req.query.column, 10)
const { imageName } = req.query
@ -201,12 +204,13 @@ function syncFromCode(req, res, next) {
line,
column,
{ imageName, editorId, buildId, compileFromClsiCache },
function (error, pdfPositions) {
function (error, pdfPositions, downloadedFromCache) {
if (error) {
return next(error)
}
res.json({
pdf: pdfPositions,
downloadedFromCache,
})
}
)
@ -216,7 +220,8 @@ function syncFromPdf(req, res, next) {
const page = parseInt(req.query.page, 10)
const h = parseFloat(req.query.h)
const v = parseFloat(req.query.v)
const { imageName, editorId, buildId, compileFromClsiCache } = req.query
const { imageName, editorId, buildId } = req.query
const compileFromClsiCache = req.query.compileFromClsiCache === 'true'
const projectId = req.params.project_id
const userId = req.params.user_id
CompileManager.syncFromPdf(
@ -226,12 +231,13 @@ function syncFromPdf(req, res, next) {
h,
v,
{ imageName, editorId, buildId, compileFromClsiCache },
function (error, codePositions) {
function (error, codePositions, downloadedFromCache) {
if (error) {
return next(error)
}
res.json({
code: codePositions,
downloadedFromCache,
})
}
)

View file

@ -23,6 +23,7 @@ const {
downloadLatestCompileCache,
downloadOutputDotSynctexFromCompileCache,
} = require('./CLSICacheHandler')
const { callbackifyMultiResult } = require('@overleaf/promise-utils')
const COMPILE_TIME_BUCKETS = [
// NOTE: These buckets are locked in per metric name.
@ -447,12 +448,20 @@ async function syncFromCode(projectId, userId, filename, line, column, opts) {
'-o',
outputFilePath,
]
const stdout = await _runSynctex(projectId, userId, command, opts)
const { stdout, downloadedFromCache } = await _runSynctex(
projectId,
userId,
command,
opts
)
logger.debug(
{ projectId, userId, filename, line, column, command, stdout },
'synctex code output'
)
return SynctexOutputParser.parseViewOutput(stdout)
return {
codePositions: SynctexOutputParser.parseViewOutput(stdout),
downloadedFromCache,
}
}
async function syncFromPdf(projectId, userId, page, h, v, opts) {
@ -465,9 +474,17 @@ async function syncFromPdf(projectId, userId, page, h, v, opts) {
'-o',
`${page}:${h}:${v}:${outputFilePath}`,
]
const stdout = await _runSynctex(projectId, userId, command, opts)
const { stdout, downloadedFromCache } = await _runSynctex(
projectId,
userId,
command,
opts
)
logger.debug({ projectId, userId, page, h, v, stdout }, 'synctex pdf output')
return SynctexOutputParser.parseEditOutput(stdout, baseDir)
return {
pdfPositions: SynctexOutputParser.parseEditOutput(stdout, baseDir),
downloadedFromCache,
}
}
async function _checkFileExists(dir, filename) {
@ -522,9 +539,10 @@ async function _runSynctex(projectId, userId, command, opts) {
return await OutputCacheManager.promises.queueDirOperation(
outputDir,
/**
* @return {Promise<string>}
* @return {Promise<{stdout: string, downloadedFromCache: boolean}>}
*/
async () => {
let downloadedFromCache = false
try {
await _checkFileExists(directory, 'output.synctex.gz')
} catch (err) {
@ -535,13 +553,14 @@ async function _runSynctex(projectId, userId, command, opts) {
buildId
) {
try {
await downloadOutputDotSynctexFromCompileCache(
projectId,
userId,
editorId,
buildId,
directory
)
downloadedFromCache =
await downloadOutputDotSynctexFromCompileCache(
projectId,
userId,
editorId,
buildId,
directory
)
} catch (err) {
logger.warn(
{ err, projectId, userId, editorId, buildId },
@ -554,7 +573,7 @@ async function _runSynctex(projectId, userId, command, opts) {
}
}
try {
const output = await CommandRunner.promises.run(
const { stdout } = await CommandRunner.promises.run(
compileName,
command,
directory,
@ -563,7 +582,10 @@ async function _runSynctex(projectId, userId, command, opts) {
{},
compileGroup
)
return output.stdout
return {
stdout,
downloadedFromCache,
}
} catch (error) {
throw OError.tag(error, 'error running synctex', {
command,
@ -686,8 +708,14 @@ module.exports = {
stopCompile: callbackify(stopCompile),
clearProject: callbackify(clearProject),
clearExpiredProjects: callbackify(clearExpiredProjects),
syncFromCode: callbackify(syncFromCode),
syncFromPdf: callbackify(syncFromPdf),
syncFromCode: callbackifyMultiResult(syncFromCode, [
'codePositions',
'downloadedFromCache',
]),
syncFromPdf: callbackifyMultiResult(syncFromPdf, [
'pdfPositions',
'downloadedFromCache',
]),
wordcount: callbackify(wordcount),
promises: {
doCompileWithLock,

View file

@ -22,6 +22,9 @@ const fs = require('node:fs')
// projectId -> timestamp mapping.
const LAST_ACCESS = new Map()
let ANY_DISK_LOW = false
let ANY_DISK_CRITICAL_LOW = false
async function collectDiskStats() {
const paths = [
Settings.path.compilesDir,
@ -30,6 +33,8 @@ async function collectDiskStats() {
]
const diskStats = {}
let anyDiskLow = false
let anyDiskCriticalLow = false
for (const path of paths) {
try {
const { blocks, bavail, bsize } = await fs.promises.statfs(path)
@ -45,10 +50,16 @@ async function collectDiskStats() {
})
const lowDisk = diskAvailablePercent < 10
diskStats[path] = { stats, lowDisk }
const criticalLowDisk = diskAvailablePercent < 3
anyDiskLow = anyDiskLow || lowDisk
anyDiskCriticalLow = anyDiskCriticalLow || criticalLowDisk
} catch (err) {
logger.err({ err, path }, 'error getting disk usage')
}
}
ANY_DISK_LOW = anyDiskLow
ANY_DISK_CRITICAL_LOW = anyDiskCriticalLow
return diskStats
}
@ -70,11 +81,22 @@ async function refreshExpiryTimeout() {
break
}
}
Metrics.gauge(
'project_persistence_expiry_timeout',
ProjectPersistenceManager.EXPIRY_TIMEOUT
)
}
module.exports = ProjectPersistenceManager = {
EXPIRY_TIMEOUT: Settings.project_cache_length_ms || oneDay * 2.5,
isAnyDiskLow() {
return ANY_DISK_LOW
},
isAnyDiskCriticalLow() {
return ANY_DISK_CRITICAL_LOW
},
promises: {
refreshExpiryTimeout,
},
@ -125,12 +147,12 @@ module.exports = ProjectPersistenceManager = {
)
})
// Collect disk stats frequently to have them ready the next time /metrics is scraped (60s +- jitter).
// Collect disk stats frequently to have them ready the next time /metrics is scraped (60s +- jitter) or every 5th scrape of the load agent (3s +- jitter).
setInterval(() => {
collectDiskStats().catch(err => {
logger.err({ err }, 'low level error collecting disk stats')
})
}, 50_000)
}, 15_000)
},
markProjectAsJustAccessed(projectId, callback) {

View file

@ -1,11 +1,11 @@
clsi
--data-dirs=cache,compiles,output
--dependencies=
--docker-repos=gcr.io/overleaf-ops,us-east1-docker.pkg.dev/overleaf-ops/ol-docker
--env-add=ENABLE_PDF_CACHING="true",PDF_CACHING_ENABLE_WORKER_POOL="true",ALLOWED_IMAGES=quay.io/sharelatex/texlive-full:2017.1,TEXLIVE_IMAGE=quay.io/sharelatex/texlive-full:2017.1,TEX_LIVE_IMAGE_NAME_OVERRIDE=gcr.io/overleaf-ops,TEXLIVE_IMAGE_USER="tex",DOCKER_RUNNER="true",COMPILES_HOST_DIR=$PWD/compiles,OUTPUT_HOST_DIR=$PWD/output
--docker-repos=us-east1-docker.pkg.dev/overleaf-ops/ol-docker
--env-add=ENABLE_PDF_CACHING="true",PDF_CACHING_ENABLE_WORKER_POOL="true",ALLOWED_IMAGES=quay.io/sharelatex/texlive-full:2017.1,TEXLIVE_IMAGE=quay.io/sharelatex/texlive-full:2017.1,TEX_LIVE_IMAGE_NAME_OVERRIDE=us-east1-docker.pkg.dev/overleaf-ops/ol-docker,TEXLIVE_IMAGE_USER="tex",DOCKER_RUNNER="true",COMPILES_HOST_DIR=$PWD/compiles,OUTPUT_HOST_DIR=$PWD/output
--env-pass-through=
--esmock-loader=False
--node-version=20.18.2
--node-version=22.15.1
--public-repo=True
--script-version=4.7.0
--use-large-ci-runner=True

Some files were not shown because too many files have changed in this diff Show more