Compare commits

..
433 Commits
Author SHA1 Message Date
Andrew Rumble 028bca6e87 Merge pull request #30798 from overleaf/ar-reapply-request-overrides
[monorepo] reapply request overrides

GitOrigin-RevId: 55d19cc011435a00ffc1e5c63f523473cd0fc2dc
2026-01-16 09:56:13 +00:00
Alf Eaton 03a3518aae Merge pull request #30703 from overleaf/ae-prettier
Upgrade Prettier to v3.7.4

GitOrigin-RevId: 0f4434019bc7d12f2d5b7ecbb833ee20570d0706
2026-01-16 09:56:07 +00:00
Jessica Lawshe 3f19aaa58e Merge pull request #30697 from overleaf/jel-fix-new-managed-user-via-account-linking
[web] Throw error if new user via domain capture not opted to be managed

GitOrigin-RevId: 1e18447ea337854d39f8e89df52ef20f8f1d382f
2026-01-16 09:05:26 +00:00
Jessica Lawshe ca1a78163b Merge pull request #30760 from overleaf/ii-domain-capture-page-content-updates
[web] Update domain capture page content

GitOrigin-RevId: b70b82bcfca4db8e55ddcc961c0ec2d32af130e6
2026-01-16 09:05:21 +00:00
Thomas 7206771eca Merge pull request #30790 from overleaf/tm-update-react-router-dom
Update react-router-dom to 6.30.3

GitOrigin-RevId: 728e3182a214af3e1f257a45a0ca3b4284672be8
2026-01-16 09:05:13 +00:00
Andrew Rumble 4271744bfd Merge pull request #30606 from overleaf/ar/bump-qs-to-6.14.1
[monorepo] bump qs to 6.14.1

GitOrigin-RevId: 4b1f8b1cf739c3c0195392fa6707fc233d036b70
2026-01-15 14:20:06 +00:00
l-obrien-overleaf 3694322f5b Applying colour styling on close symbol palette in dark theme (#30724)
GitOrigin-RevId: 3c8ce6552fce431923d008b245efe6948375e003
2026-01-15 14:20:02 +00:00
Alf Eaton 36432ffb5b Clamp pos when storing scroll position (#30773)
GitOrigin-RevId: b381950e209c18a5fbba07604839b7c3eac90da8
2026-01-15 14:19:57 +00:00
Davinder Singh 9e9b5b22cf Merge pull request #30567 from overleaf/ds-mj-dark-mode-project-list
[web] Adding dark mode project list on Dashboard

GitOrigin-RevId: ed678b1ffa8abb776eed46fb3b4b88deedd3b62c
2026-01-15 14:19:49 +00:00
Gernot Schulz f78940ea0d Merge pull request #30783 from overleaf/gs-jenkins-noorg-links
Remove `Overleaf_Organization` folder from links

GitOrigin-RevId: 6da82bd306da4ece8fa3931cf65eee4e7e35ecea
2026-01-15 14:19:45 +00:00
Andrew Rumble 2cdbdc1291 Merge pull request #30785 from overleaf/ar-add-logs-for-no-projectHistoryId-from-web
[document-updater] add log for missing projectHistoryId from web

GitOrigin-RevId: 750150312e341ef09b6c82b9df467900beb4b784
2026-01-15 14:19:37 +00:00
Jakob Ackermann 14a7e935b8 [web] override timeout for a specific template (#30711)
* [web] override timeout for a specific template

* [web] fix junit integration for vitest

* [web] consolidate on JUNIT_ROOT_SUITE_NAME

* [web] fix unit test

GitOrigin-RevId: 3ba865e4b9c090c7bf8e07dc3d81e9bcee20d821
2026-01-15 14:19:33 +00:00
Jakob Ackermann 95f0dac343 [clsi-cache] add sharded disk layout (#30763)
* [clsi-cache] remove old DiskCrawler

* [clsi-cache] use helpers for populating state during initial crawl

* [clsi-cache] use path helpers everywhere

* [clsi-cache] create project folder as part of the initial crawl

* [clsi-cache] add sharded disk layout

* [k8s] clsi-cache: switch clsi-cache-zone-b-shard-0 to new disk layout

* [clsi-cache] tweak logging context

* [monorepo] add bin/format_project_key util

* [k8s] clsi-cache: use a single nginx config file

GitOrigin-RevId: bb49146502cc6201eef210efae33355321efd77b
2026-01-15 14:19:28 +00:00
Andrew Rumble a071cd74bc Merge pull request #30784 from overleaf/revert-30675-ar-jpa-log-missing-history-id-docupdater
Revert "[document-updater] add additional logging when doc is missing projectHistoryId"

GitOrigin-RevId: 725508a8f88ad3354b8b4644f4ee1e91efbecde2
2026-01-15 14:19:24 +00:00
Alf Eaton 23255fe264 Downgrade @codemirror/view to 6.38.6 (#30776)
GitOrigin-RevId: bb123c35674b0c21959e1532adc5cdb957f9aa89
2026-01-15 14:19:15 +00:00
Andrew Rumble 258c6224f4 Merge pull request #30675 from overleaf/ar-jpa-log-missing-history-id-docupdater
[document-updater] add additional logging when doc is missing projectHistoryId

GitOrigin-RevId: fba311cb10e0eeeb0a8165ce4e519c7704a7458f
2026-01-15 14:19:11 +00:00
Malik Glossop a0fc14b367 Merge pull request #30495 from overleaf/mg-context-menu-paste
[web] Support paste with formatting in context menu

GitOrigin-RevId: 551ed1d49ca423395bd9bfc756e10e8d59d71ecd
2026-01-15 14:19:03 +00:00
Malik Glossop f087d125c1 Merge pull request #30168 from overleaf/mg-context-menu
Add context menu (right click) to editor

GitOrigin-RevId: f2e567b51b04170ba1a46b0ab4659f3481b05bfe
2026-01-15 14:18:58 +00:00
Okan Sahiner 5e38efb6b2 Merge pull request #30563 from overleaf/jpa-cleanup-c2d
[monorepo] finish migration from n2d to c3d and c2d to c4d

GitOrigin-RevId: ffdedd41e11559c9cf32dc49e891f31adcecd515
2026-01-15 09:06:57 +00:00
Alex Vizcaino 6523ffe57e Add pagination and "show more" functionality to publications list (#30720)
GitOrigin-RevId: 934a1da4f1a326d833cb25de37759f9c63f16571
2026-01-15 09:06:42 +00:00
jmescuderowritefull 6e203c1a5f A/B test with a new design which encourages prompting for paraphrase (#30478)
GitOrigin-RevId: 91d1ae18fd41dfe8edaa1592b2083c9aa7724b68
2026-01-15 09:06:35 +00:00
Jimmy Domagala-Tang d17c2fb47d feat: expressify and async await remaining callback code in UserMembershipMiddleware (#30424)
GitOrigin-RevId: 2f36587557b6cbfbd8b6ba0ccfc49564dbcabf79
2026-01-15 09:06:27 +00:00
Jimmy Domagala-Tang 7f3c8a281d Async await entity providers (#28841)
* fix: async await entity providers

* fix: async await userMembershipGetters

* fix: move to export class style for UserMembershipsHandler

* fix: update how Publisher model returns its v1 values

GitOrigin-RevId: f94bcb81c9703deaf938cdf7dff31c6e24dc4bd8
2026-01-15 09:06:23 +00:00
Alf Eaton 9b6eab9251 Allow text selection in log entry header (#30638)
GitOrigin-RevId: 18c6c9bc9b2971dbd877ce7d053a2582c6d072ad
2026-01-15 09:06:14 +00:00
Alf Eaton 5204ec5d0b Ensure that change decorations are mapped through updates (#30663)
GitOrigin-RevId: 9529e308594b771191f71751478c2118bd91a84e
2026-01-15 09:06:10 +00:00
Alf Eaton 5d16fa207a Upgrade CodeMirror and Lezer dependencies (#30615)
* Upgrade CodeMirror and Lezer dependencies
* Ensure that BraceWidget and IconBraceWidget always have string content
* Add updateDOM to BraceWidget
* Use pinned versions
* Fix description list decoration

GitOrigin-RevId: 5306f7f09290eb9a2c375e97d33509537f3c5e5f
2026-01-15 09:06:05 +00:00
ilkin-overleaf 291f882aa2 Merge pull request #30514 from overleaf/ii-cms-launchpad-typescript
[web] Convert cms and launchpad to TypeScript

GitOrigin-RevId: d2b38671a2389206dafc7bd50c28cf0bb9683601
2026-01-15 09:05:54 +00:00
Jessica Lawshe 9a4896a0b3 Merge pull request #30690 from overleaf/ii-domain-capture-mu-enrollment-changes
[web] Managed user enrollment page updates

GitOrigin-RevId: c05a29bd6cac7fd8fd25d3e8765d91e2b4d7306d
2026-01-15 09:05:49 +00:00
Jessica Lawshe 0b83bbba25 Merge pull request #30698 from overleaf/jel-account-linking-managed-users
[web] Do not show option to add email on account linking page for groups with managed users

GitOrigin-RevId: cb36ad1afd4c1bd84009a871adfbb01703227376
2026-01-15 09:05:45 +00:00
Miguel Serrano af2be7c074 [git-bridge] Update envsubst and dependencies (#30747)
Updates patch versions of stable dependencies, and rebuilds
envsubst

GitOrigin-RevId: f55bc2d5c00aef110cf6a8ba89e8529211d560cb
2026-01-15 09:05:37 +00:00
Jakob AckermannandBrian Gough 023f39ded9 [clsi] try harder at sending files off to a working clsi-cache shard (#30673)
* [clsi] try harder at sending files off to a working clsi-cache shard

* [clsi] use a crc for generating a stable sequence of shards to try

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

* [clsi] gradually migrate to crc based shard assigment

* [clsi] tweak selecting clsi-cache shard from crc

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

* [clsi] bump rollout dates of new clsi-cache shard change

---------

Co-authored-by: Brian Gough <brian.gough@overleaf.com>
GitOrigin-RevId: 9386e170503b405580e4d0a8641832f3fcb1fa83
2026-01-15 09:05:26 +00:00
Rebeka Dekany 7e19998d15 Show video controls on iOS mobile devices by default (#30737)
* Add controls for Safari iOS video autoplay

* Show controls for all iOS mobile devices

GitOrigin-RevId: a086b127c1e56543a08341474b77de57171ea8c2
2026-01-15 09:05:22 +00:00
Domagoj Kriskovic 6c76d1cd4c Check preferences for track changes before sending email
GitOrigin-RevId: 99206cf438b18d90bca2db9d6db2a6676008a72d
2026-01-15 09:05:17 +00:00
Domagoj KriskovicandEric Mc Sween 4e2ea44b61 [web] add BibTeX visual editor module (#30726)
* [web] add BibTeX visual editor module

* Make the visual editor hook open to extension

Instead of looking specifically for the bibtex visual editor, allow any
extension to provide a visual editor.

* Fix stylelint error

---------

Co-authored-by: Eric Mc Sween <5454374+emcsween@users.noreply.github.com>
GitOrigin-RevId: c85c27a2b119c826e3d00cbd475a2a21f1508091
2026-01-15 09:05:13 +00:00
Tim Down 64da16f0d1 Merge pull request #28670 from overleaf/td-rename-validate-req
Rename validateReq to parseReq

GitOrigin-RevId: a935aaa3f89495e164ce5d10b0bd80436571440f
2026-01-15 09:05:09 +00:00
Mathias Jakobsen 6e5e53f4e6 Merge pull request #30717 from overleaf/mj-new-editor-fps-e2e
[server-ce] Add new E2E for full project search to redesigned editor

GitOrigin-RevId: 3487a9a85c57d17dea91d8e35f22355a24d55008
2026-01-14 10:18:16 +00:00
Miguel Serrano 74724d04be [CE/SP] Force rebuild of Base Image (#30723)
Forces a rebuild of the CE/SP base image, updating
OS dependencies and installing the latest version of node.

GitOrigin-RevId: a172b7cf1b19e303ea19d4392ee43f7043bb96ad
2026-01-14 10:18:11 +00:00
Mathias Jakobsen b9acc4f586 Merge pull request #30715 from overleaf/msm-full-project-search-sp
[web] Enable Full Project Search in SP for new/old editor

GitOrigin-RevId: f569a45fff3b2c716db7acab3aae4ddbf80903c9
2026-01-14 10:18:07 +00:00
Mathias Jakobsen 19545b35d8 Merge pull request #30637 from overleaf/mj-ce-sp-new-editor
[web] Release editor redesign to Community Edition and Server Pro

GitOrigin-RevId: 062779fb418e44a4b245572fab1b4f365585a7f0
2026-01-14 10:18:02 +00:00
Miguel Serrano 422b474a17 [web] update_institution_user_saml_ids.mjs script (#30691)
The update_institution_user_saml_ids.mjs script updates `samlIdentifiers.externalUserId`
for users with a specific `samlIdentifiers.providerId`, performing a string replacement.

GitOrigin-RevId: 9d9897b17a528ea2ef3abf60d3b5e6679bf11943
2026-01-14 10:17:57 +00:00
Simon Gardner c8e0fd0477 [web] Add logout to list of managed group user events
GitOrigin-RevId: 3d90d315742888934cc2561be323247d75c3f977
2026-01-14 10:17:46 +00:00
Simon Gardner bb7b8ee227 [web] Add audit log entries for project-history-version-restore and project-history-version-download
GitOrigin-RevId: 8cfe1fee733aa886cd6518d352abd95bd9da6f77
2026-01-14 10:17:40 +00:00
Olzhas Askar 3f7555e5a0 Merge pull request #30674 from overleaf/oa-import-coupons
[web] Simplify and allow multiple promotion codes

GitOrigin-RevId: 6ac1115bcdf4298579df33b3896ee0b786720bac
2026-01-14 09:05:55 +00:00
Jimmy Domagala-Tang 69f3f29f50 Dark mode for project list survey (#30619)
* feat: add dark mode for project list survey

* theming hover states on buttons

* feat: move theming to re-useable mixin

GitOrigin-RevId: ed85d050e908ae13d97ee8d67cf74e00c27fc258
2026-01-14 09:05:51 +00:00
Jimmy Domagala-Tang a204f30d0f Add dark mode for cookie-banner (#30559)
* feat: adding dark mode for cookie-banner

* feat: move most relevant cookie-banner styles to footer

* fix: consistent naming for css vars, and scoping dark mode to only applicable pages for cookie Banner

* fix: swapping to themed border var

GitOrigin-RevId: 7de36cdeae6802a96a6983c739ab6fc95dee7e28
2026-01-14 09:05:47 +00:00
Tim Down 2b39beab80 Merge pull request #29697 from overleaf/ac-td-user-audit-log-index
Add migration to improve index on userAuditLogEntries

GitOrigin-RevId: c4a606e1ab7299008baa3b05ac1fb8ca18036fae
2026-01-14 09:05:31 +00:00
Andrew Rumble 27950a42b4 Merge pull request #30585 from overleaf/ar/bump-storybook-plugins
[web] bump storybook plugins to 8.6.15

GitOrigin-RevId: dc3d0ed496dab490902f556ec019fa57a75c635f
2026-01-14 09:05:27 +00:00
Jessica Lawshe d570ac2ec9 Merge pull request #30503 from overleaf/jel-managed-user-project
[web] Show notification on admin page when project is owned by managed user

GitOrigin-RevId: 015f94a8e277709ab4fec7736ac49c5ff2b7740d
2026-01-13 09:07:41 +00:00
Jessica Lawshe c2ef50f563 Merge pull request #30176 from overleaf/jel-domain-capture-email-exists
[web] Show message when email from domain capture SAML callback is on another user's account

GitOrigin-RevId: 24b440f368c15811cc5b18623238abcc2a88329f
2026-01-13 09:07:30 +00:00
Domagoj Kriskovic da7569e892 Revert "[project-history] migrate from joi to zod (#30187)" (#30681)
This reverts commit f8396a3caadd536edf64c6f971c77f4c941f000a.

GitOrigin-RevId: 8d66aa15a29216736755c3f86954a4d40aa20a6c
2026-01-13 09:07:22 +00:00
9cc2a7f1e0 [clsi-cache] cache templates in GCS and create entries on-demand (#30614)
* [clsi-cache] cache templates in GCS and create entries on-demand

* [clsi-cache] add missing return

Co-authored-by: Daniel Kontsek <daniel.kontsek@overleaf.com>

* [clsi-cache] update build scripts

* [web] fix unit tests

* [web] run prettier (again)

* [clsi-cache] drop 1xx prefix from submissionId

* [clsi-cache] add bestEffortRmDir helper

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

---------

Co-authored-by: Daniel Kontsek <daniel.kontsek@overleaf.com>
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
GitOrigin-RevId: e4bd7dca5611f16d9a6e76f2e7cf83e5819fa610
2026-01-13 09:07:17 +00:00
Mathias Jakobsen 69b12f3075 Merge pull request #30632 from overleaf/mj-pdf-dark-mode-tear-down
[web] Tear down pdf-dark-mode feature flag

GitOrigin-RevId: 5f3fa98af8eba70139ec614a3c2e08e380b56de9
2026-01-13 09:07:12 +00:00
Mathias Jakobsen 1b272483cd Merge pull request #30651 from overleaf/mj-chat-token-members
[web] Hide chat for restricted token members

GitOrigin-RevId: 2bf4dbbc2f0ebf863a73669543a13700cc25df8c
2026-01-13 09:07:08 +00:00
Domagoj Kriskovic 6d3dd3601a [project-history] migrate from joi to zod (#30187)
* Add @overleaf/validation-tools in project-history

* use error handler for zod

* Replace joi validations with zod schema

* fix unit tests

* remove Joi validation middleware

* remove optional when there is a default

* fix tests after checking for objectid

* ran build_scripts

* monorepo npm install

GitOrigin-RevId: f8396a3caadd536edf64c6f971c77f4c941f000a
2026-01-13 09:07:00 +00:00
Jakob Ackermann 18cff6e1ac [object-persistor] import ProjectKey helper from history-v1 (#30600)
GitOrigin-RevId: c72aa4bf91569904a2072c74d6ed2f3c764d97bb
2026-01-13 09:06:55 +00:00
Jakob Ackermann 292230b1db [web] inline trivial mongo queries when creating project from template (#30601)
GitOrigin-RevId: 7aefee892d491b1ec191d07bf1871317b897dec8
2026-01-13 09:06:47 +00:00
Jakob Ackermann 72ad614b25 [web] remove fallback for old clsi-server-id persistence (#30528)
GitOrigin-RevId: bd29aa1f77d61b5ff0c2c0a7d6fa893509c89e37
2026-01-13 09:06:43 +00:00
Jakob Ackermann 425e7b1e5b [web] enable mongo notablescan in CI (#29501)
* [monorepo] record ERROR/FATAL log messages in junit report

* [web] put SaaS specific code behind feature flag

* [web] use split test cache for getting user assignments

The unit tests needed updating as they did not replicate any of the
 mongo filtering. The acceptance tests cover this logic.

* [web] make better use of existing indexes

* [web] avoid col-scan in tests of notifications module

* [web] remove cleanup of empty feedbacks collection

* [web] add assertion for reason of rejected request in launchpad test

* [web] add missing indexes

* [web] enable mongo notablescan

* [web] make emailNotifications tests compatible with notablescan

GitOrigin-RevId: b888f2feeb3a0e915f068ae1c4ea23ec17821221
2026-01-13 09:06:38 +00:00
Andrew Rumble 3073c94522 Merge pull request #30215 from overleaf/ar/convert-real-time-to-esm
[real-time] convert real time to esm

GitOrigin-RevId: 7cc530cc977549d3274be42585735e1fd72cad5f
2026-01-13 09:06:30 +00:00
Mathias Jakobsen b54bed0dd2 Merge pull request #30621 from overleaf/mj-no-opt-out-split-test
[web] Add feature flag for removing old editor switcher

GitOrigin-RevId: 98b60214686ff5fa002e249e0cd8550d0c54c240
2026-01-13 09:06:21 +00:00
Mathias Jakobsen db9d075cda Merge pull request #30636 from overleaf/mj-tear-down-editor-redesign-flag
[web] Remove editor-redesign feature flag

GitOrigin-RevId: e03cad9398b381c48074da171c2c7853681cfd71
2026-01-13 09:06:17 +00:00
Miguel Serrano 0cfc97bc72 [web] project-downloaded audit logs (#30075)
Adds new `project-downloaded` and makes it available
to managed group admin.

GitOrigin-RevId: 5ae406182f87590acf300f8095a6c7e6c25366c0
2026-01-13 09:06:08 +00:00
Mathias Jakobsen a341af2e66 Merge pull request #30562 from overleaf/mj-reshow-old-editor-tooltip
[web] Reshow old editor deprecation notice

GitOrigin-RevId: a1adfaa6f807880e2e3f7d20ce4ea8c2b486da1a
2026-01-13 09:05:57 +00:00
Alf Eaton d8cbe651cd Reduce brightness of primary colour in dark mode (#30486)
GitOrigin-RevId: 12fddbe998317a8c3e405479ab666b3035fe202b
2026-01-13 09:05:52 +00:00
Andrew Rumble b35ff1f33e Merge pull request #30583 from overleaf/ar/increase-v1-timeout
[web] increase timeout for v1 requests to 60 seconds

GitOrigin-RevId: 0deb5e5d5fbe6b63d12263f223d76e6aa83b20a5
2026-01-13 09:05:47 +00:00
Maria Florencia Besteiro Gonzalez 3261ffa4d0 Merge pull request #30539 from overleaf/mfb-promisify-cooldown-manager
promisify cooldown manager

GitOrigin-RevId: 88c8c7d7e306042524ecd400fb15527206472cb1
2026-01-13 09:05:43 +00:00
Kristina 29f5026dda [web] fix import products script when tax code is null (#30605)
GitOrigin-RevId: 32ca603376db7f186283514067178d27038a865d
2026-01-12 09:07:16 +00:00
Alf Eaton 5f20651607 Ensure that @writefull dependencies are transpiled to browserslist targets (#29551)
GitOrigin-RevId: e8070679e79c16e81d8e14061cbb9c41781009a0
2026-01-12 09:06:55 +00:00
Domagoj Kriskovic 0a84cefc96 Revert "Record project notification timestamp in Redis on applyUpdate (#29509)"
This reverts commit faa7a97fa929941cade5d62d2d680c6c3f34cdc8.

GitOrigin-RevId: 31c88ee836fb5e1ab3950da590c28e24b1397edb
2026-01-12 09:06:50 +00:00
Mathias Jakobsen 3d5e84d264 Merge pull request #30598 from overleaf/mj-templates-file-menu-button
[web] Add template management button to new editor

GitOrigin-RevId: 64aec2d771f551fc75d3a1e6f3c684842e1086f4
2026-01-12 09:06:41 +00:00
Mathias Jakobsen e895ff8153 Merge pull request #30549 from overleaf/mj-build-script-minio-certs
[build-scripts] Handle expired certs in minio

GitOrigin-RevId: 7e0d03112790fbbfd0c2a1718e272aeeb99c8767
2026-01-12 09:06:36 +00:00
Brian Gough e4eb116a5c Merge pull request #30609 from overleaf/bg-additional-check-for-upload-file-leak
handle file tree operation errors in uploadFile

GitOrigin-RevId: 00ebb8318c38cb13b45733774d1328ae20ebc97a
2026-01-12 09:06:31 +00:00
Brian Gough b3c2146b6f Merge pull request #30530 from overleaf/bg-fix-zip-upload-leak
clean up temporary folder on zip upload failure

GitOrigin-RevId: 83a934f41de7e4c737bb3e1123e6ac6b0cb15429
2026-01-12 09:06:26 +00:00
Brian Gough 6b4b733da1 Merge pull request #30527 from overleaf/bg-acf-fix-file-upload-leak
clean up temporary file on upload failure

GitOrigin-RevId: 0f30e6da2087e94e2e9bb95ae845af2efdaa5a7b
2026-01-12 09:06:21 +00:00
Domagoj Kriskovic c461d4d8c3 Rename doc updater script to use .mts extension
GitOrigin-RevId: 43d84434ee91aa579cb049081a31cb3769844320
2026-01-12 09:06:12 +00:00
Domagoj Kriskovic 8bca2545ee Record project notification timestamp in Redis on applyUpdate (#29509)
* Record project notification timestamp in Redis on applyUpdate

* Refactor project notification timestamp recording in Redis

* Remove tests which are catching errors that are no longer used

GitOrigin-RevId: faa7a97fa929941cade5d62d2d680c6c3f34cdc8
2026-01-12 09:06:07 +00:00
jmescuderowritefull 239e89a0a8 Enable toolbar generators only when they are runnable (#30470)
GitOrigin-RevId: a9671121d938f480c9f108f9f7c480524da38bee
2026-01-09 09:07:48 +00:00
Antoine Clausse e0f8aca331 Merge pull request #30613 from overleaf/revert-30251-ac-dismiss-ciam-notification
[web] Revert "Make CIAM login notification dismissible (with cookies)"

GitOrigin-RevId: d7b7fac350dbc5479487341800320d4917f27d1b
2026-01-09 09:07:31 +00:00
Antoine Clausse 31ab47a534 [web] Make CIAM login notification dismissible (with cookies) (#30251)
* Extend notifications so they can be dismissed

The dismissal is stored in a cookie for a year

* Extend CIAM notifications so they can be dismissed

* Make the CIAM notification dismissable

* Style the close button so it is in the corner of the notification

* Add e2e test

* [e2e] Replace 'not.exist' by 'not.be.visible'

* Set cookie with the same pattern as the "cookie-banner cookie"

* Hide notification in the frontend

* Revert "Hide notification in the frontend"

This reverts commit b5d205f3e3a4e2555be038eb3b7561761a2cde59.

* Add `data-ol-dismiss-cookie-paths` to the notification

* Add `data-ol-dismiss-cookie-paths` to the notification (CIAM variant)

* Shorten cookie name

* Revert: remove the .corner class

* Apply design from Figma for CIAM notifications

GitOrigin-RevId: 4070715c6a63d0497b7a41c343c3f943ced4bfef
2026-01-09 09:07:26 +00:00
Antoine Clausse 7dc937b0f0 [real-time] Promisify RealTimeClient (#30500)
* Define `Client` at the end of the file

* Promisify `setSession`

* Promisify `setAnonSession`

* Remove unused `unsetSession`

* Promisify `connect`

* Promisify `getConnectedClients`, add `@overleaf/fetch-utils`

* Promisify `countConnectedClients`

* Promisify `getConnectedClient`

* Promisify `disconnectClient`

* Promisify `disconnectAllClients`

* Remove decaffeinate comment

GitOrigin-RevId: 4b0b376cdae5b1b69fe7e66b131d4b2ec7059eaa
2026-01-09 09:07:19 +00:00
Alf Eaton 861b66b007 Revert "Cite an article by pasting the DOI (#29994)" (#30607)
This reverts commit a68af023b24fcf87bbc608395f2898df8e9b41a5.

GitOrigin-RevId: c0dd9ae3f6a0e12e6ba7d1e856327ea89eae8157
2026-01-09 09:07:14 +00:00
Maria Florencia Besteiro Gonzalez 5e753dd8eb Merge pull request #30123 from overleaf/mfb-docs-site-could-link-to-devs-site-when-it-errors
Mfb docs site could link to devs site when it errors

GitOrigin-RevId: ce250c93a316dfff6d8dd28d107fdba7cb7c5b08
2026-01-09 09:07:10 +00:00
Alf Eaton 7275551690 Use themed colours for editor toggle switch (#30487)
GitOrigin-RevId: 32406f92555722406a636f9c3db9bea3ca9dac10
2026-01-09 09:07:03 +00:00
Alf Eaton 10eca3070c Strip inline cite markers from response text (#30477)
GitOrigin-RevId: af4af74e989c042bb8174854e79f3ba29193ac80
2026-01-09 09:06:58 +00:00
Alf Eaton 18b2621855 Cite an article by pasting the DOI (#29994)
GitOrigin-RevId: a68af023b24fcf87bbc608395f2898df8e9b41a5
2026-01-09 09:06:51 +00:00
Alf Eaton 22d717583f Upgrade core-js and Babel (#29554)
GitOrigin-RevId: 259149f10335d98443fa8e6ccc4289d2bb3138dd
2026-01-09 09:06:46 +00:00
Alf Eaton ff0eb6696b Merge pull request #30437 from overleaf/ae-glob
Use glob 10.5.0
Remove babel/cli (#30438)

GitOrigin-RevId: aa5477c2f8afff63ac80f90718601ec64f3238e2
2026-01-09 09:06:42 +00:00
Alf Eaton cfe7300177 Add stylelint as a dev dependency (#30084)
GitOrigin-RevId: 302b7bd1054984d39ab2f9aa25a0666c38608a3b
2026-01-09 09:06:37 +00:00
Alf Eaton d1db34bcf0 Upgrade TypeScript to 5.9 (#30433)
GitOrigin-RevId: 7b11f258c0188f69fabd8fd0da709e0979fc8a4a
2026-01-09 09:06:33 +00:00
Alf Eaton 3986bae603 Upgrade AI dependencies (#30432)
GitOrigin-RevId: 9f431a8a16f4e30043895198ebeaf62234f86180
2026-01-09 09:06:29 +00:00
Alf Eaton b69797e3f4 Set min-width on search form position element (#30473)
GitOrigin-RevId: 6f65eba9589f14f7d22668e925d819467c0ad4bd
2026-01-09 09:06:21 +00:00
Alf Eaton b4ff3f15ad Tear down full-project-search-promo (#30474)
GitOrigin-RevId: 9af516202bdf281b11348726667037fa458d66d9
2026-01-09 09:06:17 +00:00
Alf Eaton 5badb39259 Avoid closing nested menu on click (#30479)
GitOrigin-RevId: 0f966b53ee5bfd8b4bacdf7b259f3e8cab2858c8
2026-01-09 09:06:12 +00:00
Alf Eaton b54bbc6cff Add Button variants story (#30491)
GitOrigin-RevId: 98d0cd965832de79de493d46ef9c989daff7be9b
2026-01-09 09:06:08 +00:00
Alf Eaton 64104e069a Add IdeRedesign decorator to dropdown menu stories (#30493)
GitOrigin-RevId: c63801c50029f17979c2b1c0e02a3b0ba5fb7adf
2026-01-09 09:06:04 +00:00
Alf Eaton ce5f66c21b Add keyboard shortcuts for Layout actions (#30494)
GitOrigin-RevId: 7978a579e719c4cd593c02662406e364b19f87e0
2026-01-09 09:05:56 +00:00
Domagoj Kriskovic 6de0273d45 Process notifications by grouping them per project with caching (#30439)
* Add caching for project updates and file diffs in notifications processing

* Simplify filterNotificationsByPreferences function

* NotificationsEmailBuilder class

* fix cachedRecipient issue

* change processing to group per project

* remove updates cache

* clear cache after processing a project

* refactor: update sendNotificationsForProject to accept project as parameter

* fix unit tests

* apply review suggestions

* feat: add migration script for updating emailNotifications indexes

* refactor: update sendNotificationsForProject to accept projectId

* refactor: simplify fileTreeDiff result assigning

* fix tests

GitOrigin-RevId: bfed061864ba7314f85cf97b7adaeef62c8c5f00
2026-01-09 09:05:42 +00:00
ilkin-overleaf 7931c7b3eb Merge pull request #30471 from overleaf/ii-linkedin-insight-tag
[web] Add Linkedin Insight tag

GitOrigin-RevId: f01e1908ad945a5db10343a04ee50104efa32c3c
2026-01-09 09:05:38 +00:00
ilkin-overleaf e0483dd6c3 Merge pull request #30460 from overleaf/ii-await-csrf
[web] Promisify Csrf

GitOrigin-RevId: 00e1d8e3d79c58e4cb614574415cba3a1b21f1f2
2026-01-09 09:05:33 +00:00
Mathias Jakobsen 5e49f421c2 Merge pull request #30405 from overleaf/dp-cleanup-editor-redesign-opt-out-2
(Re)Cleanup editor-redesign-opt-out feature flag

GitOrigin-RevId: afefced1f77de2b8b27e1333ffa647ac41561e31
2026-01-09 09:05:29 +00:00
Eric Mc Sween f2a70de6ef Merge pull request #30366 from overleaf/mj-em-package-meta
[web] Add event for package usage

GitOrigin-RevId: e994becf01e7e4c8642cd1815ffe05907a5fd63c
2026-01-08 09:05:53 +00:00
Jimmy Domagala-Tang 75734993e7 Add Notification Preferences Page To User Settings (#30116)
* changing to pug conditional format for admin page conditional render

* feat: update notifications settings page and open BE route

feat: adding new page for notification prefs on user settings, along with updating saving prefs for global preferences

adding error handling and disabling when request is inflight

formatting and adding split test for viewing notification ettings

fix: updating to levels of preferences, and removing global type for preferences as we will now share the same backing settings between global and project preferences

feat: add global mute to user settings for notifications

making params in preferences schema optional

feat: update global settings to only set mute, and remove optional settings

fix: store userId as objectId, and filter based on global mute setting
GitOrigin-RevId: 947a95dc02d12b4a2d8e3cc29bd04c23af2aef25
2026-01-08 09:05:49 +00:00
Jimmy Domagala-Tang 9a6c2edf16 changing to pug conditional format for admin page conditional render (#30302)
GitOrigin-RevId: 38006bc5378151219e7c219f292c167ed27bb38e
2026-01-08 09:05:44 +00:00
Antoine Clausse 7d9f7f131b Merge pull request #30578 from overleaf/revert-30394-revert-30391-dp-test-revert-1
Revert "[web] Reapply: Promisify ProjectLocator (#30319)"

GitOrigin-RevId: 2752266fe84d69ffb9e31c65c7872f58be861ec9
2026-01-08 09:05:34 +00:00
Rebeka Dekany 5c61ea53d5 Include Stripe couponCode and promotionCode in analytics events (#29873)
* Include valid couponCode and promotionCode in `payment-page-view` and `payment-page-form-submit` analytics events

* Update payment event types

* Remove obsolete comment

* fix: only send validated coupon and promotion codes in analytics event

* Add coupon name for the analytics events

* Update test to include the coupon name for analytics

* Remove coupon code from analytics

* Simplify promotion code validation using coupon.code

* Remove undefined

* Allow access to promotion code

* Remove `lastValidatedPromotionCode` and compare against coupon code from the preview response

* Fix test setup to initialize coupon code

* Keep the submit button enabled only when the coupon code is either empty or successfully validated by the backend

* Update test coupon code value to TEST_COUPON

GitOrigin-RevId: b12fa147d91fd3b90b59bc77868a0786ddb633b7
2026-01-08 09:05:27 +00:00
Antoine ClausseandBrian Gough 16b83b128b [web] Promisify ProjectRootDocManager (#30327)
* Remove ESLint disable

* Unnest ProjectRootDocManager methods

* Promisify `setRootDocAutomatically`

* Promisify `findRootDocFileFromDirectory`

* Promisify `setRootDocFromName`

* Promisify `ensureRootDocumentIsSet`

* Promisify `ensureRootDocumentIsValid`

* Promisify `_sortFileList`

* Fixup export

* Call `ProjectRootDocManager.promises.setRootDocAutomatically` so mocks work

* Update ProjectRootDocManager.test.mjs

* Remove expects on callbacks

* Add `return` on the first matching entry in `setRootDocAutomatically`

See https://github.com/overleaf/internal/pull/30327#discussion_r2624011209

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

---------

Co-authored-by: Brian Gough <brian.gough@overleaf.com>
GitOrigin-RevId: f83e8239f65776d23b49cb7a569181abc7c9a276
2026-01-08 09:05:12 +00:00
Antoine Clausse 3d352b35cb Merge pull request #30394 from overleaf/revert-30391-dp-test-revert-1
[web] Reapply: Promisify ProjectLocator (#30319)

GitOrigin-RevId: 0cde095b81ea61211881b6b29fa4dd58d952a162
2026-01-08 09:05:08 +00:00
Andrew Rumble 538af8c445 Merge pull request #30455 from overleaf/dependabot-npm_and_yarn-storybook-8.6.15
Bump storybook from 8.6.12 to 8.6.15

GitOrigin-RevId: b4b47eff80a42c902ea8e81a659a989c148b51ef
2026-01-08 09:04:56 +00:00
Jakob Ackermann 32ad596e54 [clsi] minor fixes for clsi-cache (#30551)
* [clsi] fix circuit breaker for clsi-cache

* [clsi] enable ts-check for CLSICacheHandler

* [clsi] limit the number of .blg files in clsi-cache to 50

* [clsi-cache] limit the number of files per job to 100

* [clsi-cache] explain early registration of buildId

* [clsi-cache] lock down downloads via nginx to project folder

GitOrigin-RevId: 081d0c40b08db3a384c4d765b71a50b973f42151
2026-01-07 09:06:30 +00:00
Mathias Jakobsen 0fc0e54cf5 Merge pull request #29325 from overleaf/dp-git-bridge-aws-sdk
[git-bridge] Update AWS S3 SDK

GitOrigin-RevId: c40f6c0c3eef6e45e27a57462a7a4732d5151c26
2026-01-07 09:05:57 +00:00
Eric Mc Sween 9ca39b7854 Merge pull request #30336 from overleaf/em-promisify-web-api-manager
Promisify WebApiManager

GitOrigin-RevId: d86ed972b714d55e864ff630935ae4068933ca39
2026-01-07 09:05:48 +00:00
Mathias Jakobsen 750ef6ca19 Merge pull request #30510 from overleaf/mj-git-bridge-persistent-swap-local
[git-bridge] Make git-bridge data persistent

GitOrigin-RevId: e5e7ec613db455b21b4f96c9bf8e6829cc02a4ce
2026-01-07 09:05:43 +00:00
Mathias Jakobsen bf662f74f5 Merge pull request #30458 from overleaf/mj-git-bridge-local-swap
[git-bridge] Mock S3 locally with minio

GitOrigin-RevId: d56659d601e4450f69332202b86e61a443375101
2026-01-07 09:05:38 +00:00
Mathias Jakobsen 32845170ff Merge pull request #30497 from overleaf/mj-git-bridge-staging-swap
[git-bridge] Reduce amount of projects on staging git bridge disk

GitOrigin-RevId: 428825f354487ece20b2538e7d312186d56cc03a
2026-01-07 09:05:33 +00:00
ThomasandJakob Ackermann 9be3c3fd76 refactor: update Makefile to use conditional assignment (#30295)
* refactor: update Makefile to use conditional assignment

Co-authored-by: Jakob Ackermann <jakob.ackermann@overleaf.com>
GitOrigin-RevId: a00592608e3377701ec75617eef995ce4b05a95b
2026-01-06 09:06:22 +00:00
Andrew Rumble 0ca1888f76 Merge pull request #29374 from overleaf/renovate-major-vitest-monorepo
chore(deps): update vitest monorepo to v4 from ^3.2.4 (major)

GitOrigin-RevId: 553a8fefadd82598a9ff4089ce468b59791e2d43
2025-12-18 09:06:39 +00:00
Rebeka Dekany cbeb58cc0a Use Sidebar as the name for the rails navigation (#30301)
GitOrigin-RevId: a24f8822f3208a2c1dedb6d424cf243fc3409ed1
2025-12-18 09:06:34 +00:00
Alf Eaton a841dbfd2c Add "Set as main document" to file tree menu (#30399)
GitOrigin-RevId: e05a7d0b103226bdc34e559d0d48c12183abdf5a
2025-12-18 09:06:19 +00:00
Alf Eaton fa62723682 [workbench] Remove raw HTML support (#30396)
GitOrigin-RevId: 9fb75c173be83771042a91804cad878152a6fc8f
2025-12-18 09:06:11 +00:00
Alf Eaton ffd2b2120e [workbench] Use lightbulb_2 icon for thinking (#30303)
GitOrigin-RevId: 26346ce1f70ab419188bb9de503572e05d928ff9
2025-12-18 09:05:59 +00:00
Mathias Jakobsen 82cb0e2839 Merge pull request #30312 from overleaf/mj-mock-web-api-async
[document-updater] Remove callbacks from MockWebApi

GitOrigin-RevId: 0189d5735f3e90160e593fb04043a10b1e922685
2025-12-18 09:05:55 +00:00
Mathias Jakobsen ea4dcd4452 Merge pull request #30311 from overleaf/mj-mock-project-history-async
[document-updater] Remove callbacks from MockProjectHistoryApi

GitOrigin-RevId: b85702bfeeba2dc124880c2b590148514b4e89cb
2025-12-18 09:05:51 +00:00
Mathias Jakobsen 6f67ae4312 Merge pull request #30310 from overleaf/mj-async-mock-docstore-api
[document-updater] Remove callbacks from MockDocstoreApi

GitOrigin-RevId: 86342f293e9bbbcaddd6c44bcca62c301db23670
2025-12-18 09:05:46 +00:00
Mathias Jakobsen c4fb6233ce Merge pull request #30308 from overleaf/mj-host-admin-async
[server-ce] Promisify host-admin.js

GitOrigin-RevId: 18adf72113bb26aaaa1dbf89e3ea6dd6c242239b
2025-12-18 09:05:42 +00:00
Anna Claire Fields 06a0cf2391 Merge pull request #30339 from overleaf/acf-migration5-cleanup
(5) Remove swagger dependencies from history-v1

GitOrigin-RevId: d3d79dd9d3c8ccb59d6a59aeede7186daf18bdb0
2025-12-18 09:05:37 +00:00
Domagoj Kriskovic c30b348668 For editing/deleting chat messages ensure user is a message author
GitOrigin-RevId: d7d4f1bb9f004d8fed8644f0aabe621ed863437b
2025-12-18 09:05:22 +00:00
Miguel Serrano 48e7f8042b [git-bridge] Update jetty to v12 (#30221)
GitOrigin-RevId: 44b3f754b3dbced8a2ac47472e113ef4cae30c50
2025-12-18 09:05:13 +00:00
Daniel Kontšek b79a723630 Merge pull request #30397 from overleaf/dn0-fix-jenkins-worker-build
Fix failing jenkins-worker builds

GitOrigin-RevId: 3fcd2a3f791c811c04c5e3861cf64e9adf7d5f91
2025-12-17 09:23:54 +00:00
Miguel Serrano c12fe12b13 [CE/SP] Force rebuild of base image (#30400)
GitOrigin-RevId: 32e8b96e8ed74bf7f51e52058cd71ca7636d8f50
2025-12-17 09:23:48 +00:00
David bf384683f0 Merge pull request #30393 from overleaf/dp-test-revert-2
Revert "Merge pull request #29916 from overleaf/dp-cleanup-editor-red…

GitOrigin-RevId: c2f14fb55e74a1fcb026e37822774724c36bc0dc
2025-12-17 09:07:15 +00:00
Antoine Clausse 9aa7a36721 Merge pull request #30391 from overleaf/dp-test-revert-1
Revert "[web] Promisify ProjectLocator (#30319)"

GitOrigin-RevId: 4db2e86424619bb032512da7a6718d30a04e7990
2025-12-17 09:07:10 +00:00
Eric Mc Sween 969079125a Merge pull request #30386 from overleaf/revert-30335-em-retry-octokit
Revert github-sync octokit migration

GitOrigin-RevId: d9f89e058e4ef9f5e6c157089be2793168db9170
2025-12-17 09:07:05 +00:00
Antoine Clausse a82b969db7 [web] Promisify ProjectLocator (#30319)
* Promisify ProjectLocator

* Update ProjectLocator unit tests

GitOrigin-RevId: 5d657a9da81de6788f8543ad00d7a374e7d54747
2025-12-17 09:07:00 +00:00
Antoine Clausse 657d7b952f [web] Add missing period to advancing_research_with (#30377)
GitOrigin-RevId: a19e2c1b0716a6a4d9105a806fd3af5797e6f2bc
2025-12-17 09:06:55 +00:00
David 1d831b5776 Merge pull request #29916 from overleaf/dp-cleanup-editor-redesign-opt-out
Cleanup editor-redesign-opt-out feature flag

GitOrigin-RevId: 6a1dc6908fa6276181f9e3996e0b14cfb7537786
2025-12-17 09:06:46 +00:00
Alex Vizcaino efcf776a2d Remove standalone citations checker components and related logic (#30378)
GitOrigin-RevId: 1b4dd5d2e0588472ae4c8daf10186d49606aaf78
2025-12-17 09:06:34 +00:00
Eric Mc Sween d496324b8d Merge pull request #30335 from overleaf/em-retry-octokit
Retry github-sync migration to octokit

GitOrigin-RevId: d34b2498e86039dd0781a1707adbfe523acfa250
2025-12-17 09:06:13 +00:00
jmescuderowritefull 60b8aef82d Do not let users to suggest languages that are already supported (#30354)
GitOrigin-RevId: 4fe91e4f581d5775366cdd94023954efd2af79ed
2025-12-17 09:06:00 +00:00
Kristina 4acf79cd54 [web] only emit assistant-add-on-purchase for add-on purchases (#30288)
GitOrigin-RevId: 084e28f02d348fe5504a38f1405250ea2f7b67ce
2025-12-17 09:05:51 +00:00
Antoine Clausse 039491f866 [web] Promisify NotificationsHandler (#28805)
* Replace request by fetch

* Promisify NotificationsHandler.js

* Replace to `fetchNothing` when we don't consume the body.

I also checked that these endpoints don't return anything: https://github.com/overleaf/internal/blob/de2d0ed8cab15c4347ddecf227073a6d4e06120f/services/notifications/app.js

* Make URLs safer

* Ignore (but log) failing `fetchNothing`s on DELETE endpoints

* Defensively add `userId.toString()` to prevent bugs (!)

* Update NotificationsHandler unit tests

* Throw fetch errors only if we did not get a response

GitOrigin-RevId: 03700ad29658c0e3af4e476b25a964030e9c97f1
2025-12-17 09:05:38 +00:00
Alex Vizcaino 5f5125b3fa [Citation Reviewer] Error Management (#30356)
GitOrigin-RevId: 9a34fab4f5447974e795a49c548b8af730857e88
2025-12-16 09:08:01 +00:00
Alex Vizcaino bba00b3589 [citation-reviewer] clear search functionality and update translations in citations reviewer (#30343)
GitOrigin-RevId: 76a3e69785bb115a3d2ba202ff36a4c9851f7771
2025-12-16 09:07:48 +00:00
Brian Gough 1416a59f87 Merge pull request #28830 from overleaf/bg-async-await-github-sync
migrate github-sync AuthenticationController to async/await

GitOrigin-RevId: 0d0cdc0dcb054dd36c9b1323ea1003678c75f6a2
2025-12-16 09:07:31 +00:00
Domagoj Kriskovic 7b00e5d9f5 Add routes to save/get project notification preferences (#30114)
* Add routes to save/get project notification preferences

* update route url

* improve zod schema

* remove unused json response

* update schema and fix tests

* add jsdoc types to pass type-check

* remove using zod strict()

GitOrigin-RevId: f3ab5c88b58bd5af71e0504d0efbe03bdf9b243c
2025-12-16 09:07:07 +00:00
ilkin-overleaf 3b32b0a61e Merge pull request #30317 from overleaf/ii-recurly-subscription-id-not-found
[web] Show group members page when recurly subscription does not exist

GitOrigin-RevId: 8855af6ca1ad92cec437cabd2fe9425671d8ea23
2025-12-16 09:06:58 +00:00
ilkin-overleaf 4801174f68 Merge pull request #30188 from overleaf/ii-domain-capture-group-sso-link
[web] Improved `group-sso-link` logs

GitOrigin-RevId: 426dfa46c5c3a236382744fe408f33df81c5a9a0
2025-12-16 09:06:53 +00:00
Anna Claire Fields 65c164c73d Merge pull request #30053 from overleaf/acf-migration4-controllers-and-params
(4) Update controllers and tests for Zod migration

GitOrigin-RevId: 876fd64f96e1f5d7244ac1d45053c7db9857d46b
2025-12-16 09:06:44 +00:00
Mathias Jakobsen 0efb28baa7 [web] Tweak basic rate limiter for workbench (#30280)
GitOrigin-RevId: 3e2c2f03e88339ee18e393cb7044ed15e95e51a5
2025-12-15 09:06:16 +00:00
Alf Eaton 5af113d85d Upgrade Streamdown and mdast-util-to-hast (#30270)
GitOrigin-RevId: bce694a6d5d84403f134afd0038576bc1aabadd7
2025-12-15 09:06:11 +00:00
Alf Eaton 953eba1d0d Avoid beta badge focus when word count modal is opened (#30281)
GitOrigin-RevId: 570002a4dade41d393c66508e36c2863840f57f6
2025-12-15 09:06:06 +00:00
Liangjun Song 2706c91b25 Merge pull request #30285 from overleaf/ls-skip-webhook-event-for-admin-user-id-removal
Skip webhook event for admin user id removal

GitOrigin-RevId: f5b3b3543bf4efcbf0d99caa6325259132823c77
2025-12-12 09:06:36 +00:00
Kristina c6fc921c11 [web] add script for updating prices for existing Stripe subscriptions (#30216)
GitOrigin-RevId: 8f20a6ba9c7a737bb304d8698c4fbcb06b6ddc8c
2025-12-12 09:06:32 +00:00
Liangjun Song 2a4a245b6f Merge pull request #30263 from overleaf/ls-stop-writing-admin-user-id-metadata
Stop writing adminUserId metadata

GitOrigin-RevId: f8230a6b9d9f50afb16feceb0efa6f0b888302d4
2025-12-12 09:06:27 +00:00
David cf11b336ba Merge pull request #30040 from overleaf/dp-dark-file-drag
Fix file tree dragging item colors

GitOrigin-RevId: e8f8148d837404bab034a302acc1c9273e09e399
2025-12-12 09:06:23 +00:00
Andrew Rumble ef4341a541 Merge pull request #30279 from overleaf/ar/add-esm-import-eslint-rules
[monorepo] add esm import eslint rules

GitOrigin-RevId: 5637bb1107aa034701cae2e37a85cc3d8d8036d2
2025-12-12 09:06:19 +00:00
Olzhas Askar 7cc91e7254 Merge pull request #29831 from overleaf/visible-coupon-input
[web] Visible coupon input

GitOrigin-RevId: 491783c5b0027990fa54af92dcdd1d7af718cf23
2025-12-12 09:06:11 +00:00
Olzhas AskarandDaniel Kontsek 38b4ff72cd Replace learn with learnwiki (#30259)
* feat: replace learn with learnwiki

* revert: for sharelatex

* Change `MW_SERVER` env variable to `learnwiki`

---------

Co-authored-by: Daniel Kontsek <daniel.kontsek@overleaf.com>
GitOrigin-RevId: 97cdf034ed864d1620b5fd8673f0a7fe64056e01
2025-12-12 09:06:03 +00:00
Brian Gough 44cb381a4d Merge pull request #30244 from overleaf/bg-add-missing-configuration-for-pdf-caching
add missing configuration for pdf caching

GitOrigin-RevId: b5791d5d6db7fc9e970acaa0ca9cc43e1a7ca8ec
2025-12-12 09:05:55 +00:00
jmescuderowritefull ef2ad9eea8 Add notification for translation (#30003)
GitOrigin-RevId: 7c837f8d81f8fe74ea7b7f262f036129cbbd005a
2025-12-12 09:05:43 +00:00
Andrew Rumble bc09edc240 Merge pull request #30092 from overleaf/ar/convert-analytics-to-esm
[analytics] convert to ESM

GitOrigin-RevId: 2d3903a0f0e7c5a0baac90538b1cdc800ddd888c
2025-12-12 09:05:35 +00:00
Alf Eaton d9e266d654 [workbench] Add translations (#30240)
GitOrigin-RevId: 014933dcd749390bb73bd2bc12d0e4799093b4dd
2025-12-12 09:05:27 +00:00
Alf Eaton f941cbab5f Update workbench events (#30254)
GitOrigin-RevId: 7434483ce125676f1d7d76dfcb09d6691f9dadef
2025-12-12 09:05:19 +00:00
Mathias Jakobsen efe7cf0064 Merge pull request #30237 from overleaf/ae-workbench-popover
Add a popover to the AI assistant rail button

GitOrigin-RevId: 5bc141ba10ef0bc798ab79a847d73804d60353d6
2025-12-12 09:05:15 +00:00
Mathias Jakobsen b554b0cfcc Merge pull request #28497 from overleaf/mj-system-editor-theme-dark-light-split
[web] Split editor theme into two when using system overall theme

GitOrigin-RevId: 1efa5553fdff8a17de634017882feb2ede614cd6
2025-12-12 09:05:10 +00:00
Lucie Germain 96a071dd04 Merge pull request #30262 from overleaf/lg-locales-readme-remove-onesky
Remove OneSky from Locales readme

GitOrigin-RevId: b0bf685497537465227d17956f61636dc9866ba4
2025-12-11 09:06:09 +00:00
Liangjun Song 7effe4630f Merge pull request #29982 from overleaf/ls-group-ownership-transfer
Stripe subscription ownership transfer

GitOrigin-RevId: 8285f635ecc220595782fbea6def74fdc9a92f36
2025-12-11 09:05:57 +00:00
Tim Down 427419e6a5 Merge pull request #30233 from overleaf/td-select-check-icon
Fix regression with select check icon

GitOrigin-RevId: c76e126c26395429cd3d41ac4e6ee36259062224
2025-12-11 09:05:33 +00:00
Andrew Rumble 4a415a602d [monorepo] Upgrade node-forge to >=1.3.2 (#30209)
Merge pull request #30209 from overleaf/ar/bump-node-forge-to-1.3.2

GitOrigin-RevId: e53162bc412c84f9a125dc351247b172fe1b4096
2025-12-11 09:05:24 +00:00
Antoine Clausse 4ff590e28b [web] Avoid overriding button hover styles in button-links (#30230)
* Avoid overriding button styles in button-links

* Remove now unnecessary btn background override in button-links

GitOrigin-RevId: 2f47b461b6d66f1f5bbbf93b32c197cd53ca959a
2025-12-10 09:07:44 +00:00
jmescuderowritefull 2dc6677370 Feedback for Citation Review (#30214)
GitOrigin-RevId: dcd00ead7940d3fe76aa32b2cdbb617a2c86a4fb
2025-12-10 09:07:36 +00:00
Alex Vizcaino 7d30c87aa3 Citation Reviewer custom searcher (#30225)
GitOrigin-RevId: 8762fdce9001de0c332e1c72a667fe3f40b020c5
2025-12-10 09:07:31 +00:00
Tim Down 38f2b5e616 Merge pull request #30198 from overleaf/td-ciam-misc-fixes
Miscellaneous CIAM fixes

GitOrigin-RevId: b7f38888b602fc7b4dc4fbc63e38f82527ab666e
2025-12-10 09:07:18 +00:00
Antoine Clausse d0d0776d25 [web] Misc. CIAM fixes (#30196)
* Remove focused style from the stepper

* Reduce spacing between password input and password policy

* Make input validation icon larger

* Make animated-tick.svg faster

* Move notification to below h1

* Move notification to below h1

* Fix: Warning: Invalid DOM property `autocomplete`. Did you mean `autoComplete`?

* Wrap form-text in a span so it's displayed correctly and not altered by flex

* Remove "Please request a new password reset email and follow the link." text after the email is entered

* Remove (unnecessary?) flex property on .ciam-form-text-icon

* Rename `messageTextNode` to `messageTextSpan`

* Revert changes to input-validator.ts

GitOrigin-RevId: ad83c92a59b9dbc872cf4e49362b0baec9fb5b93
2025-12-10 09:07:13 +00:00
Alf Eaton b811da0695 [workbench] Improve asynchronous tool use (#30184)
GitOrigin-RevId: d1bd33469b557c29968049af99b9c3c85731151d
2025-12-10 09:06:43 +00:00
Alf Eaton 851f0c92b1 Upgrade AI dependencies (#30202)
GitOrigin-RevId: 829f359c3d8c5b6abb2dbf0eca4c8bd3dec284be
2025-12-10 09:06:31 +00:00
Brian Gough 42d09010aa Merge pull request #30174 from overleaf/bg-history-backup-allow-stalled-jobs-to-be-retried
Allow stalled jobs to be retried in backup queue settings

GitOrigin-RevId: c68605aa89e9f8d4c2bc11fc14739a7d0774096d
2025-12-10 09:06:18 +00:00
Malik Glossop 96141d7abe Merge pull request #30195 from overleaf/mj-svg-path-id-clash
[web] Resolve id clash for svg paths

GitOrigin-RevId: 911d44a4b1549d8de0cae39658f05660e75c180f
2025-12-10 09:05:54 +00:00
Rebeka Dekany 7921e9852f Remove non-functional ejs overrides from service packages (#30178)
GitOrigin-RevId: 495fb629aa53d44bf7f097a7a92e4963c99fe58f
2025-12-10 09:05:49 +00:00
Malik Glossop 4462472e33 Merge pull request #30027 from overleaf/mg-svg-figure-modal
Support svg files in figure modal

GitOrigin-RevId: 4f0e110dad3c06f5e5ac699e0bfcaf3cd6c784ff
2025-12-10 09:05:44 +00:00
David ddbc40693b Merge pull request #30192 from overleaf/dp-file-outline-link
Update file outline empty state link

GitOrigin-RevId: 1f83c0d0010f6a48ff03d6b9464b4d8764630d85
2025-12-10 09:05:40 +00:00
Antoine Clausseand@copilot 549840f3a3 [web] Add unified-access-footer-click event (#30189)
* Add event `unified-access-footer-click`

* Remove redundant `page` segmentation

Co-authored-by: @copilot
GitOrigin-RevId: 81ba64d09e29466fb73f200859805b6e17990dca
2025-12-10 09:05:35 +00:00
David c903c70d0a Merge pull request #30180 from overleaf/dp-dark-context-menu
Add dark version of file tree context menu

GitOrigin-RevId: de37cd6b78e32ace295a9c77fbba86d4ba217b80
2025-12-10 09:05:30 +00:00
Andrew Rumble f3c9b2f2f0 Merge pull request #30182 from overleaf/ar/update-jws-to-3.2.3_or_4.0.1
[monorepo] update jws to 4.0.1

GitOrigin-RevId: b3e778b26b2860112fe80220d6e7354520994082
2025-12-10 09:05:25 +00:00
jmescuderowritefull c86593327b Feedback for citation review (#30141)
GitOrigin-RevId: a629f1e24f901695e42af18ade4b57753834e758
2025-12-09 09:06:50 +00:00
Antoine Clausse fa9e667373 [web] Misc. changes to CIAM pages (#30181)
* Remove double dots

* Make skip button Tertiary instead of Link

* Bold email

* New zotero logo

GitOrigin-RevId: 569fa4c18fc85abf55b492f7033472445c63ed6b
2025-12-09 09:06:37 +00:00
Tim Down f8e87929e1 Merge pull request #30150 from overleaf/td-ciam-welcome-storybook
Add CIAM welcome interstitial page

GitOrigin-RevId: 6d333b4d3256e6af2604fbf6363bce7079c4c1ab
2025-12-09 09:06:28 +00:00
Mathias Jakobsen 0b51972da1 Merge pull request #28503 from overleaf/mj-split-theme-list-dark-light-legacy
[web] Split dark and light options in theme selector

GitOrigin-RevId: 507c5a71269b360d23b246516487a0a072ee7d18
2025-12-09 09:06:07 +00:00
Antoine Clausse da72a45e86 [web] Requested changes to email verification screens (#30173)
* no grey hyphen when the input is empty

* show email in bold

* Fix tests

* Add test to verify email display in confirmation code input

* Format

GitOrigin-RevId: ade4a670b9dc80b99f64cc3273407a98428521b8
2025-12-09 09:05:46 +00:00
Antoine Clausse 567c81054a [web] Add collapsible info to ODC (#30164)
* Add collapsible info in ODC

* Remove transition effects on caret

* Update summary focus-visible style

Make it inline-block so the clickable part doesn't go out of bounds.
Update outline style.

* Make the caret orientation consistent with Figma and Dashboard

* Remove extra padding

* Make `summary` styled like ds btn-tertiary

See https://www.figma.com/design/qHqSob0u4b4h1i2ModSTLn/CIAM---Phase-01?node-id=2285-20806&t=AlQIeoQEd2kG2h2M-0

GitOrigin-RevId: 9a49efe68088ea4969a803ffaa1c981c5a7ed7bb
2025-12-09 09:05:40 +00:00
Antoine ClausseandTim Down 6eefe6dda4 [web] Create CIAM versions of the password reset screens (#30087)
* Make CIAM copies of Pug files

passwordResetCiam.pug
setPasswordCiam.pug

* Update controller with split test assignment

* Use CIAM layout in passwordResetCiam.pug

* Style passwordResetCiam according to designs

* Use CIAM layout in setPasswordCiam.pug

* Style setPasswordCiam according to designs

* Use settings value in registration screen for must_be_at_least_n_characters

* Retrieve email input with a script

* Replace mb-4 by --ds-spacing-800

* Add eye icon to toggle password visibility

* Avoid double dots after some translated strings

* Use `ciamCustomFormDangerMessage`

* Use `ciamErrorNotification`

* Use `ciamButtonContentLoading`

* Replace remaining "mb" classes

* Move new password errors to the top of the form

* Fix CIAM mixins path after rebase

* Use `ciamCustomFormDangerMessage`

* Add `data-ol-spinner-inflight` to buttons

* Replace classname ciam-notification by notification-ds

Remove borders from CIAM notifications
Fix font size

* Revert "Use settings value in registration screen for must_be_at_least_n_characters"

This reverts commit a0af95c11e171097750ad7ee871f6baf89d5c0cb.

(It's Friday afternoon so I don't want to update unrelated stuff :D)

* Update: check_your_inbox

* Remove `.ciam-card` min-height.

Unnecessary thanks to `.confirm-email-success-form`'s min-height: 400px;

* Use phosphor icons

* Style `formMessagesNewStyle` with DS notifications within CIAM pages

Alternatively, we could extend/duplicate `showMessagesNewStyle` with a CIAM variant

* Revert "Style `formMessagesNewStyle` with DS notifications within CIAM pages"

This reverts commit ed382dc1e8cdf5b916c1527f4da0a825167e9675.

* Fix styling of dynamically-created DS notifications

* Set password length info to secondary color

* Move `ciamSamlErrorNotLoggedIn` to saas-authentication module

Prevents errors in CE:

Error: ENOENT: no such file or directory, open '/overleaf/services/web/modules/saas-authentication/app/views/_mixins.pug'
    at /overleaf/services/web/app/views/_mixins/ciam_mixins.pug line 3

---------

Co-authored-by: Tim Down <158919+timdown@users.noreply.github.com>
GitOrigin-RevId: afe58f18ecee92460ab628a285b6edb48a5c678d
2025-12-09 09:05:31 +00:00
Brian Gough b9888957e4 Merge pull request #30000 from overleaf/bg-extend-backup-blob-script
extend backup blob script

GitOrigin-RevId: 226e624f0fd93bfe4890acce728ce8005f9787c5
2025-12-08 09:06:05 +00:00
Olzhas Askar 6a93b6e76a Merge pull request #30093 from overleaf/oa-sub-marketing
[web] Enrich subscription data with details for marketing

GitOrigin-RevId: b2a07264e516ed4fac4643d0a64a8a1656c6fd13
2025-12-08 09:06:01 +00:00
ilkin-overleaf f959329337 Merge pull request #30002 from overleaf/ii-domain-capture-send-email-to-admin
[web] Send member limit notification email to group admin

GitOrigin-RevId: 520fef0dd3eab52bfb766f6f116cb4b8533b4cae
2025-12-08 09:05:53 +00:00
ilkin-overleaf 3f0dc71d6c Merge pull request #29823 from overleaf/ii-domain-capture-member-limit-check
[web] Domain capture member limit check

GitOrigin-RevId: bce12fc67aee9cbcc40a10e91585b39def4dfdf6
2025-12-08 09:05:48 +00:00
Mathias Jakobsen 25a4a2c462 [web] Default workbench to wider panel (#30156)
GitOrigin-RevId: 65c7f8b89ff9468b07017454e9eca6e11850ac7b
2025-12-08 09:05:32 +00:00
Anna Claire Fields 56c98ac99c Merge pull request #29968 from overleaf/acf-migration3-express-routes
(3) Create Express routes (replaces swagger-router)

GitOrigin-RevId: e27973b630509312b198be899148310e69b94777
2025-12-08 09:05:20 +00:00
Brian Gough a45c39389c Merge pull request #29891 from overleaf/bg-docupdater-make-max-unflushed-age-configurable
Make document-updater max unflushed age configurable via settings

GitOrigin-RevId: 3421f2467b7d8459ba8cdb1859e1b0695b0a01f3
2025-12-08 09:05:08 +00:00
Antoine Clausse a75c6a2c63 Align CIAM explanatory notification text to the left (#30144)
GitOrigin-RevId: 3d511d8a2756c9c1b1697ee040684c6e4513e0f9
2025-12-08 09:05:03 +00:00
Antoine Clausse 72a49fc97b [web] Add CIAM explanatory banner & misc. changes (#30115)
* Add CIAM explanatory banner to login page

* Center .ciam-card-footer on all sizes

* Move bottom padding to .ciam-layout

So it exists even when there is no footer

* Make every CIAM text input large

* Lint

GitOrigin-RevId: 3c5af9ffefdb064780e7818bf2fbe77c14562cd6
2025-12-08 09:04:59 +00:00
Tim Down 452d854d5b Merge pull request #29972 from overleaf/td-ciam-onboarding
Unified access onboarding data collection pages

GitOrigin-RevId: c56a3d52f749883eeb2302e22aaf6bdf1239160c
2025-12-08 09:04:54 +00:00
Brian Gough 7a57ef00cb Merge pull request #30045 from overleaf/bg-object-persistor-make-list-directory-safer
Improve safety of object persistor

GitOrigin-RevId: bced9814de6613b388ca288a5f72cd42cff6c1d3
2025-12-05 09:06:42 +00:00
Jessica Lawshe 6f34fa869d Merge pull request #30122 from overleaf/jel-fix-test
[web] Update path in test

GitOrigin-RevId: 65a1a948a137abbc2d347e1ea9a698a49d31d74d
2025-12-05 09:06:11 +00:00
Jessica Lawshe bfd618b8e4 Merge pull request #30079 from overleaf/jel-domain-capture-invited
[web] Remove invite after joining group via domain capture

GitOrigin-RevId: dda31fa7f3dad4a94d6179da7ccd2bfa2b21c605
2025-12-05 09:06:06 +00:00
Jessica Lawshe 2e3ddb0965 Merge pull request #29881 from overleaf/jel-domain-capture-email-invite-cta
[web] Update CTA for domain capture group invites

GitOrigin-RevId: addaa81c443da63124b7841f087e34145fe3bfe6
2025-12-05 09:06:02 +00:00
Jessica Lawshe 8971d05384 Merge pull request #29475 from overleaf/jel-error-when-email-not-on-account
[web] Error handling when managed user form is submitted for domain capture

GitOrigin-RevId: 33f6158edc56d46c531a90d2b3147f2bd201316c
2025-12-05 09:05:57 +00:00
Alex Vizcaino dcc675c0b8 Citations Reviewer UI/UX improvements (#30091)
GitOrigin-RevId: 60e268ea849b807032f84ea33e2969d38baac5ce
2025-12-05 09:05:52 +00:00
roo hutton 625d8efdf1 Merge pull request #30102 from overleaf/rh-price-rollback-scripts
Script for rolling back price changes in Recurly

GitOrigin-RevId: d2793b70e845ba2411814035f174a0262b99c0e9
2025-12-05 09:05:48 +00:00
Andrew Rumble 90cf4b6a0a Merge pull request #29841 from overleaf/ar-convert-filestore-to-esm
[filestore] convert to ES modules

GitOrigin-RevId: 404905973548bb6e437fff66b368e87be8249b73
2025-12-05 09:05:35 +00:00
Domagoj Kriskovic 3f6e96f58e Add email notifications settings for redesigned editor
GitOrigin-RevId: d31f13bbc668d790564618e6b4a8a83fdf2d8780
2025-12-05 09:05:26 +00:00
Kristina b9224ea11d [web] update recurly change prices script (#30006)
* update recurly change prices script
* write to /tmp/ and add an option to write to stdout
* add analytics events
* default script to renewal

GitOrigin-RevId: 5ebb17ee2c1ad70128391745a994ea6c74c739f9
2025-12-05 09:05:10 +00:00
Mathias Jakobsen ff8e9394f3 Merge pull request #30078 from overleaf/ae-workbench-code-blocks
Update code block styles

GitOrigin-RevId: b8a871ba7eb429bb5a359c823d5da0ed6717c021
2025-12-04 09:06:50 +00:00
David 2aeb788e3f Merge pull request #29946 from overleaf/dp-reopened-error
Fix go to code location on re-opened errors

GitOrigin-RevId: e7a91ae45ac44453c974c7af8ad938d21c95f410
2025-12-04 09:06:38 +00:00
David 76024341f8 Merge pull request #30058 from overleaf/dp-offscreen-context-menu
Add override for upwards dropdowns in file tree context menu

GitOrigin-RevId: 34f69f884eb0b942cb0462ab071c5dcaad8fad16
2025-12-04 09:06:33 +00:00
Tim Down f372fd07f2 Merge pull request #29869 from overleaf/mfb-archive-pdf-caching-gradual-rollouts
Mfb archive pdf caching gradual rollouts

GitOrigin-RevId: 3a2648d067c0c9cfee04fc6758bd1a5ddb44cd21
2025-12-04 09:06:15 +00:00
Tim Down 5bbc5b2e58 Merge pull request #29900 from overleaf/td-ciam-login
Implement unified access login page

GitOrigin-RevId: 9973565099e1e88dd9d6b232d8f5c545dc73e6f7
2025-12-04 09:06:11 +00:00
Anna Claire Fields c1dc70fc92 Merge pull request #29966 from overleaf/acf-migration2-security-middleware
(2) Create Express authentication middleware (replaces swagger-security)

GitOrigin-RevId: 0a15ec7ca601430a1ae00c7f81da456948650a0c
2025-12-04 09:06:06 +00:00
Alf Eaton 83db1e858f Replace react-markdown with streamdown (minus mermaid) (#29977)
GitOrigin-RevId: c78f7c537f17085fd3e8a6189c6ade59ff98eb9f
2025-12-04 09:06:02 +00:00
Alf Eaton 0b0de92444 Use unfilled icon for "Start new chat" (#30022)
GitOrigin-RevId: a8c5541bc7622cf0599c4f6674a086d0f0f388d1
2025-12-04 09:05:57 +00:00
Mathias Jakobsen a1197310c2 Merge pull request #29954 from overleaf/mj-workbench-errors
[web] Handle rate limiting and access errors

GitOrigin-RevId: f02a8764bf04da8adc41826be638ca03042fde3b
2025-12-04 09:05:46 +00:00
Mathias Jakobsen 0c07e5ff40 Merge pull request #30001 from overleaf/mj-workbench-consent-screen
[web] Add consent screen to workbench

GitOrigin-RevId: 7640154e9c02d340eb9c782e276a84cd961ad755
2025-12-04 09:05:42 +00:00
Mathias Jakobsen c4d02f4571 Merge pull request #30042 from overleaf/mj-workbench-update-labs-widget
[web] Update look of labs experiment and tweak workbench labs content

GitOrigin-RevId: f7f693f778fb659ccf10a0c440c5c7487705d98e
2025-12-04 09:05:37 +00:00
Mathias Jakobsen d531613c7a Merge pull request #30054 from overleaf/mj-workbench-title
[web] Update workbench panel title

GitOrigin-RevId: 14e505bec0d663b84b3d9dbae398f8647a30d90d
2025-12-04 09:05:33 +00:00
Alex Vizcaino 24015a4c1f Citations Checker (#29608)
GitOrigin-RevId: 2fe7720e848bf4a83ad2b71471d34ae5461e3fe9
2025-12-03 09:07:11 +00:00
Eric Mc Sween 4853352040 Merge pull request #30015 from overleaf/renovate-npm-nodemailer-vulnerability
[Core] Update dependency nodemailer to v7.0.11 from 7.0.9 [SECURITY]

GitOrigin-RevId: c3ccc9e57ece5e086b0830fb5bba249c249a2b1d
2025-12-03 09:07:02 +00:00
Miguel Serrano 8509a4cd9b Merge pull request #29645 from overleaf/msm-integration-audit-logs
[web] Reference managed linking in Group Audit Logs

GitOrigin-RevId: 82f4c15b3ccb82e27719f1970c440abe877c48ab
2025-12-03 09:06:58 +00:00
Jimmy Domagala-Tang ea5de4984f toggling on wf feature sync endpoint since we know the request load now (#30014)
GitOrigin-RevId: d7f9944caffdcb5cf42693cac7d2895026b38775
2025-12-03 09:06:49 +00:00
Domagoj Kriskovic 580fc2bad6 [notifications] include tracked changes in email notifications
GitOrigin-RevId: 01011739ef183e0fca606a5d9cbf6c23eaa14644
2025-12-03 09:06:33 +00:00
Anna Claire Fields 38ca13c26f Merge pull request #29997 from overleaf/acf-remove-trailing-dots-on-fetch
remove trailing dots on paste

GitOrigin-RevId: 486158afbec9822fd089a46d147994451d9fec65
2025-12-03 09:06:28 +00:00
Domagoj Kriskovic 3832c46f1c Skip projects that are already in new track_changes format
GitOrigin-RevId: 3162d15852664707e2072b5c7af6d3849f1d0677
2025-12-03 09:06:20 +00:00
Anna Claire Fields c25e49782f Merge pull request #29965 from overleaf/acf-migration1-validation
Add Zod validation (replaces swagger-validator + swagger-metadata)

GitOrigin-RevId: 2e4ed742e401bdfe49c6f7dc9d0fceeba20cfc7f
2025-12-03 09:06:15 +00:00
Malik Glossop 127d8273dc Merge pull request #29999 from overleaf/mg-svg-suggestion
Add svg package suggestion

GitOrigin-RevId: e2e29736a4aabb0916b619129c4afad4fd4b95b6
2025-12-03 09:06:10 +00:00
Andrew Rumble 6354310656 Merge pull request #30021 from overleaf/ar/extend-eslint-to-module-test-files
[web] extend eslint to module test files

GitOrigin-RevId: 1625362e26dd2d528c2a1d8fa5d03797cd6c011d
2025-12-03 09:06:05 +00:00
Kristina eafef60b75 [web] update Stripe archive script to avoid archiving actively used prices (#29978)
* make Stripe export script only export active products and prices
* add a gitignore for the scripts/stripe/output

GitOrigin-RevId: 975d84077c3940d4f5af518e5f8292ea455e1c3a
2025-12-03 09:05:56 +00:00
David 5982eed3fa Merge pull request #29821 from overleaf/dp-editor-redesign-opt-out
Prepare editor redesign for opt-out phase

GitOrigin-RevId: 5831970ff27e5c20f22c68b83471b6b832c2b2b4
2025-12-03 09:05:48 +00:00
Andrew Rumble a1f1ca2028 Merge pull request #29948 from overleaf/ar/docstore-conversion-to-esm
[docstore] conversion to esm

GitOrigin-RevId: 9d255047bd7ae25f2b0b38f3a721741e8a0b7ad8
2025-12-03 09:05:42 +00:00
Andrew Rumble f1e788d9b3 Merge pull request #29967 from overleaf/ar/web-remove-mocha-unit-tests
[web] remove mocha unit tests

GitOrigin-RevId: eda753af3470dbd1f385cb0bc3f06d78ade8a764
2025-12-03 09:05:37 +00:00
Miguel Serrano a3ec5b2797 Merge pull request #30018 from overleaf/msm-fix-esm-import
[web] Fix ESM import

GitOrigin-RevId: 887f4927248241cb3d237e0bdad36b05928657ef
2025-12-03 09:05:32 +00:00
Miguel Serrano fa1aa0116a [web] transfer-ownership group audit log (#29764)
* [web] `transfer-ownership` group audit log

Includes `transfer-ownership` in the list of project
audit logs visible to managed group admins, and adds logic
to add multiple log entries when more than one managed
group is involved.

GitOrigin-RevId: 780b90a74a960047e97ebba83e5502a237b83b41
2025-12-02 09:05:27 +00:00
Malik Glossop 472e05f32b Merge pull request #29971 from overleaf/mg-edit-search-bug
Make editor focusable in view-only mode

GitOrigin-RevId: ed9b079fa379d84f7f410669fa2d865f82e21cb1
2025-12-02 09:04:59 +00:00
Maria Florencia Besteiro Gonzalez dab59520c3 Merge pull request #29930 from overleaf/mfb-fix-zod-iso-datetime-error
allow iso date time string with offset on zod validation. add unit te…

GitOrigin-RevId: 88407fe681a66d13737de41789a9ea807a23627a
2025-12-01 09:06:23 +00:00
Brian Gough 06f696ced0 Merge pull request #29980 from overleaf/bg-history-extend-backup-comparison-III
Check file tree hashes in backup comparison

GitOrigin-RevId: 4bd1f36afa34f326d4b8934c8bb0ea00a52cf1d9
2025-12-01 09:06:18 +00:00
Olzhas Askar 9ebab12049 Merge pull request #29826 from overleaf/oa-coupon-scripts
[web] Coupon scripts

GitOrigin-RevId: 9d98b65649326ebad7a41c55ebce009327c9c634
2025-12-01 09:05:54 +00:00
Alf Eaton b40af34b8c Add workbench as a separate panel (#29922)
GitOrigin-RevId: de1a168e6081dee94313ba2e2a8952028cf455bb
2025-12-01 09:05:50 +00:00
jmescuderowritefull c6da21f99f Make GPT model calls in batches of 2 requests (#29944)
GitOrigin-RevId: 263c297b2bf5fb40b702f14222c6c6fadef75e8a
2025-11-28 09:06:19 +00:00
Brian Gough e0d6d7cb48 Merge pull request #29952 from overleaf/bg-history-extend-backup-comparison-II
Add batch comparison options for backup verification

GitOrigin-RevId: fe12270b4063c4105f7e7a950c6a58cd39a62843
2025-11-28 09:06:11 +00:00
Brian Gough 70909c126c Merge pull request #29950 from overleaf/bg-history-extend-backup-comparison
Add fast comparison option for blob backups

GitOrigin-RevId: e1383425487ac1b4439248f976e6106567bae07d
2025-11-28 09:06:06 +00:00
Kristina 4a9b66627e [web] update pricing settings for Nov 2025 update (#29947)
* update pricing settings for Nov 2025 update
* update `StripeLookupKeyVersion` type
* update unit tests to match new Stripe version

GitOrigin-RevId: f5df5167b605b6667cc19edad09fb2c0f72a293b
2025-11-28 09:06:01 +00:00
Andrew Rumble 07c827e9fd Merge pull request #29928 from overleaf/ar-last-infrastructure-conversions
[web] last infrastructure conversions

GitOrigin-RevId: ad1aff9b7df0610ed0303157d9e2c8032f32c02b
2025-11-28 09:05:56 +00:00
Simon Gardner 43c263b419 [web] Add audit log entry for billing-details-updated
GitOrigin-RevId: dd0079e4043d3a6ee64bd511b242d7f5649036ca
2025-11-28 09:05:47 +00:00
Simon Gardner e89a5da7de [web] Add audit log entry for group-invite-sent
GitOrigin-RevId: 70dee3b844ab1dae05f362ad7f68214959257583
2025-11-28 09:05:42 +00:00
Simon Gardner d7f7fd1d00 [web] Add Audit log entry for project send-invite
GitOrigin-RevId: 86edadc6fb95e989653b390b0f60705dce657bf2
2025-11-28 09:05:37 +00:00
Malik Glossop c7cf9f70f3 Merge pull request #29924 from overleaf/mg-cancellation-survey
[web] add cancellation survey split test

GitOrigin-RevId: acdbb83678352b34e43262d8188844e74bbe73e9
2025-11-28 09:05:28 +00:00
Mathias Jakobsen b35d70d81b Merge pull request #29789 from overleaf/mj-workbench-labs-experiment
[web] Add workbench labs experiment

GitOrigin-RevId: 9369c48ae9b818bdcce767811e284e8bfb0f9efe
2025-11-28 09:05:24 +00:00
Mathias Jakobsen 7c1a225be4 Merge pull request #29899 from overleaf/mj-dark-mode-file-flash
[web] Avoid background color flash when switching files

GitOrigin-RevId: e5d2fbb631fd54d195b9cb51b2a9db584d205138
2025-11-28 09:05:18 +00:00
Borja ff5b469b20 Enhance keyword generation logic to exclude current keywords (#29939)
GitOrigin-RevId: 04b67ac24c0d538869ecfde3a0ef9850d142ac5f
2025-11-27 09:07:03 +00:00
David dba5c380fa Merge pull request #29927 from overleaf/dp-missing-translation
Add back missing ai-assist translation

GitOrigin-RevId: 411c614b9b4a02ac2b60710414524692439b4b17
2025-11-27 09:06:58 +00:00
Gernot Schulz 74efa0e345 Merge pull request #29898 from overleaf/gs-jenkins-issues-all-pipelines
Enable Jenkins hooks for creating GitHub issues for all pipelines with owners

GitOrigin-RevId: ba46db1d3137db12ee5c78f09b126fb9927d9c49
2025-11-27 09:06:04 +00:00
Andrew Rumble 385432e8f1 Merge pull request #29921 from overleaf/revert-29914-kh-fix-import-in-scripts
Revert "[web] fix bad import in new Stripe scripts"

GitOrigin-RevId: 8bcedb2543e161fb7ae95ba6bae361c5fee7a670
2025-11-27 09:05:59 +00:00
Andrew Rumble 18f44866e5 Merge pull request #29919 from overleaf/revert-29795-ar-last-infrastructure-conversions
Revert "[web] last infrastructure conversions"

GitOrigin-RevId: 48dc64553012afb5d2db4b2eb9c9898489b7e5ef
2025-11-27 09:05:54 +00:00
Gernot Schulz 381460936b Merge pull request #29866 from overleaf/gs-jenkins-e2e-issues
Create GitHub issues from failed E2E test pipelines

GitOrigin-RevId: cad29c2f2388e04922e51039297281dc22cfd869
2025-11-27 09:05:49 +00:00
Kristina 832068c6e6 [web] fix bad import in new Stripe scripts (#29914)
GitOrigin-RevId: de3be4782ae5e5d0ee5b97e25c7103b5d1e88c9f
2025-11-27 09:05:40 +00:00
Kristina 731bf1d8b6 [web] add scripts for updating Stripe prices (#29858)
* update generate recurly prices script to skip stripe-only prices
* add script for creating new Stripe prices from a CSV
* add script to archive Stripe prices by version key
* add script for exporting Stripe products and prices
* add script to import Stripe products

GitOrigin-RevId: 3c9cf8037d956b9532c3efed5fe8d63f8be53a93
2025-11-27 09:05:35 +00:00
Andrew Rumble d748d8d606 Merge pull request #29795 from overleaf/ar-last-infrastructure-conversions
[web] last infrastructure conversions

GitOrigin-RevId: 68aa11625a9bc6d0d5324ecd95bb5ac52af8ee96
2025-11-27 09:05:30 +00:00
Mathias Jakobsen b63ce40914 [web] Move PDF dark mode button to the right (#29886)
GitOrigin-RevId: 7f423b2fb4fab61d775bc77351f1cbbc152450d1
2025-11-26 09:06:00 +00:00
Jimmy Domagala-Tang 2aa2862a77 Feat: Allow Ai Bundle for Commons Licenses (#29413)
* allowing for writefullCommonsAccount within v1 affiliates to signal a commons ai bundle

* feat: update wf when features change

* feat: replace call to wf with metric to give them estimate of number of calls

* fix: acceptance tests for GroupDomainCaptureTests rely on features outlined in settings, where aiErrorAssistant feature is not listed since it is delivered through a module hook

GitOrigin-RevId: 8c2470c7e73b8a1e080bfc977469d35e66ca9db4
2025-11-26 09:05:56 +00:00
Mathias Jakobsen 4186321ed7 [web] Add dark mode setting to PDF viewer (#29813)
GitOrigin-RevId: 4eddfac30a934c44b451694fd5e18dd8d26ad910
2025-11-26 09:05:51 +00:00
Tim Down 763bede00a Merge pull request #29654 from overleaf/ac-ciam-confirm-email-storybook
[web] CIAM design for Email confirmation form

GitOrigin-RevId: 3e66c45fe20073eb0600b8243761dbe82d7dc6b2
2025-11-26 09:05:47 +00:00
Alf Eaton 0d9fa6c0a6 Merge pull request #29853 from overleaf/ae-workbench-updates-3
[workbench] small improvements

GitOrigin-RevId: c27529004bf1521af469e42b4764f2ddd76dd023
2025-11-26 09:05:40 +00:00
Alf Eaton e590543bc5 Store PDF scroll position when the viewer unmounts (#29872)
GitOrigin-RevId: fc82c8db3d8cdf6a4857a4d2f3f62b181e40e067
2025-11-26 09:05:32 +00:00
Borja 2c00a7a3a4 fix: insert new line after inserting title, abstract or keywords (#29882)
GitOrigin-RevId: d8d79e95d9eb544adaff8850630df996461bacb9
2025-11-26 09:05:27 +00:00
Borja 4f5638348e Add keywords generation functionality (#29842)
GitOrigin-RevId: 1be8739496279af42ffbc299911db92c5caefece
2025-11-25 09:06:45 +00:00
Eric Mc Sween 1b2a52ad7f Merge pull request #29877 from overleaf/em-revert-octokit
Revert octonode to octokit migration

GitOrigin-RevId: 6a5819a0f25c96bea10bc0cae33ae90ee5038276
2025-11-25 09:06:41 +00:00
John Lees-Miller b514ebcc8e Support analytics data in user export bundle
GitOrigin-RevId: 49739297f40831cf035e2a9d4f3343a8cb2d7fdb
2025-11-25 09:06:20 +00:00
John Lees-Miller 241a4b6b03 Use worker for analytics user export
GitOrigin-RevId: 3e49d483c0d93fa67986332e77e9928889aab7a7
2025-11-25 09:06:16 +00:00
Davinder Singh ec9d2d83d8 Tear down compile-timeout-remove-info (#29719)
* tearing down the test, and removing the timeout help message

* running make cleanup_unused_locales

* npm run extract:translations

GitOrigin-RevId: 54ee19d18a86a9061ff23d6dbd8375ae0bdf73c2
2025-11-25 09:06:05 +00:00
Gernot Schulz e7c92b15cc Merge pull request #29870 from overleaf/gs-jenkins-project-opt
Add `--project` option to Jenkins issue script

GitOrigin-RevId: b38f181e1dc22687654d17c7a6b7bf185848620b
2025-11-25 09:05:57 +00:00
Eric Mc Sween ba61b0dfd4 Merge pull request #29691 from overleaf/em-promisify-github-manager
Replace octonode with octokit in github-sync

GitOrigin-RevId: dfe4f94bed8c4c41a2234860ce2b3443eb076cb9
2025-11-25 09:05:53 +00:00
Rebeka Dekany b4bfff1b67 Improve Server Pro tests to use semantic selectors (#29790)
* Replace placeholders with labels

* Add 'Close dialog' label to modal close button to distinguish from footer Close button

* Add and translate heading on the not found page

* Update textarea to have id matching label's for attribute
Simplify test for template description textarea

* Label PDF zoom level dropdown button

* Improve test selectors to use semantic roles and accessible names

GitOrigin-RevId: d215ddca30ddf844cfffbcf0e528a601b134d772
2025-11-25 09:05:48 +00:00
Simon Gardner 7dce5f0e25 Adds audit log entry for user Logout event
GitOrigin-RevId: 5a305166ba0e017ae7cb3d426cdae541e8db62c3
2025-11-25 09:05:38 +00:00
Mathias Jakobsen af148bafb3 Merge pull request #28209 from overleaf/mj-dropbox-stop-archived-sync
[web] Avoid applying TPDS updates to archived and trashed projects

GitOrigin-RevId: c33bfb1ae5975cd98c81b76713fb99369816b188
2025-11-25 09:05:33 +00:00
Mathias Jakobsen 547ae18f73 Merge pull request #29313 from overleaf/mj-ars-user-feature
[web] Convert references search to user level feature

GitOrigin-RevId: 285f68ea6624e7bad752a308cf10d06401a3e33c
2025-11-25 09:05:29 +00:00
Simon Gardner 377e431146 Update delete user audit log for managed users
GitOrigin-RevId: 5b5b164ebf5b077ec783709d6846a52e94d21565
2025-11-25 09:05:22 +00:00
Domagoj Kriskovic 6e2f999a11 Fix import from CollaboratorsHandler.js to CollaboratorsHandler.mjs (#29863)
GitOrigin-RevId: 35f7fd558a127c094b65104e0775c67dca4f96f6
2025-11-25 09:05:18 +00:00
DavidandDomagoj Kriskovic dd8451d51d Create script to update track changes stored format for all users (#26876)
* Create script to update track changes stored format for all users

* Create script to update track changes stored format for all users

* Dont remove guests

* Fix typo

* fix updateOne

---------

Co-authored-by: Domagoj Kriskovic <dom.kriskovic@overleaf.com>
GitOrigin-RevId: c2fddc46b78e84807243a752facdf0215d3ff082
2025-11-25 09:05:14 +00:00
David 44bd4ab790 Merge pull request #29802 from overleaf/dp-revert-beta
Remove hack to give beta users access to the editor redesign

GitOrigin-RevId: 40c5c2db9033dfb6569d655275e280ce29b898e2
2025-11-25 09:05:03 +00:00
David 5eca30db82 Merge pull request #29800 from overleaf/dp-outline-scroll
Remove unnecessary scrollbar from empty file outline

GitOrigin-RevId: 3866fa3653088665ee21f389174a8ad1c91b9872
2025-11-25 09:04:59 +00:00
Gernot Schulz 93e6a230c7 Merge pull request #29786 from overleaf/gs-jenkins-gh-issue-web
web: Open GitHub issue in case of pipeline failure
GitOrigin-RevId: 0adbeb4d60cd658eccde42b4ce2874ce2623908f
2025-11-25 09:04:54 +00:00
Borja d4992914c2 Add figure generator from text functionality (#29742)
GitOrigin-RevId: 94c65c567d59e3228dba63395bd46fe0c57fab02
2025-11-24 09:07:16 +00:00
Andrew Rumble e2cb424695 Merge pull request #29849 from overleaf/ar-add-missing-prism-certificate-to-web
[web] Add the missing intermediate certificate to web service

GitOrigin-RevId: 293009ae2da30f698aa0d38dc4cd902b0d8ab5e5
2025-11-24 09:07:00 +00:00
Malik Glossop abff6fccd4 Merge pull request #29847 from overleaf/mg-revert-js-yaml-change
Revert "[web] Update js-yaml to patched security version including ov…

GitOrigin-RevId: ecbb05915bdc4c21fd9e6fd6a8f74012853f1322
2025-11-24 09:06:55 +00:00
Malik Glossop 016778295a Merge pull request #29733 from overleaf/mg-transfer-ownership
Fix transfer ownership permissions

GitOrigin-RevId: b6d09704361507085e3eae8dc9240a36ae47c70e
2025-11-24 09:06:50 +00:00
Malik Glossop 68c9d1931d Merge pull request #29765 from overleaf/mg-s-patch-js-yaml
Update js-yaml to patched security version including overrides

GitOrigin-RevId: 364f4dd8fe3cb0a5c486bdf3921b42c49772e4c2
2025-11-24 09:06:45 +00:00
Tim Down 00f6a1e0f9 CIAM registration form buttons, inputs and fixes (#29740)
* Many fixes to CIAM registration form, including Phosphor icons

* Unify layout between Pug and React, fixes for spacing and mobile screen sizes

* Pug lint fix

* Make CIAM footer links underlined

* Add CIAM error notification styling

* Merge duplicate style rules

* Remove outdated comment

* Fix ordering of en.json

* Move aria-label to buttons

* Move full stop into translation string

* Remove dummy password strength indicator

* CIAM spacing and label fixes

* Header logo fixes from review

* Add aria-hidden to error icon

GitOrigin-RevId: 87c8181566f0878256b8010f95f115ec25c7ceb9
2025-11-24 09:06:40 +00:00
Mathias Jakobsen f2a05b1a2e Merge pull request #29793 from overleaf/mj-custom-rail-icon
[web] Add custom sparkles icon for workbench rail tab

GitOrigin-RevId: b332c90532e75b41b494906e021bcb49ff358024
2025-11-24 09:06:28 +00:00
Mathias Jakobsen 4a4b82cec1 Merge pull request #29797 from overleaf/mj-rail-tab-hiding-refactor
[web] Refactor tab hiding

GitOrigin-RevId: 29b4d1e67348a51e3c575ab2dda6e0931a90d504
2025-11-24 09:06:23 +00:00
Anna Claire Fields 9d2f5b3cde Merge pull request #29803 from overleaf/acf-admin-privileges-matrix
Admin privileges matrix

GitOrigin-RevId: 926c8053ab00292ee6fc0f04e0e429f307081f5e
2025-11-24 09:06:07 +00:00
Anna Claire Fields f954796709 Merge pull request #29687 from overleaf/acf-update-validator-package
Upgrade validator to 13.15.0 to fix security vulnerabilities

GitOrigin-RevId: ddafde16f9783454c332124e88dae4f164eab4f3
2025-11-24 09:05:58 +00:00
Anna Claire Fields 49e8d0c551 Merge pull request #29695 from overleaf/change-auto-compile-rate-limit
Change auto compile rate limit

GitOrigin-RevId: 9f689c4811ad03ebbbc8cf0abb5f0ac867356873
2025-11-24 09:05:53 +00:00
Brian Gough 1f356754de Merge pull request #29801 from overleaf/bg-history-refactor-backup-worker-shutdown
refactor history-v1-backup worker shutdown

GitOrigin-RevId: 9666a99b00b30e98844e7dd25932f1590d0879b3
2025-11-24 09:05:49 +00:00
Brian Gough e822ac0ee0 Merge pull request #29775 from overleaf/bg-history-use-configurable-concurrency-in-backup-worker
allow configurable concurrency for history-v1 backup worker

GitOrigin-RevId: 59c734b013f99e215cc84688142cb0fbe45b064b
2025-11-24 09:05:44 +00:00
Maria Florencia Besteiro Gonzalez e861e28296 Merge pull request #29593 from overleaf/mfb-from-joi-to-zod-analytics
[Analytics service] Migrate from JOI to ZOD

GitOrigin-RevId: 5f6abc23c5359ca8599ef4b7d660d5f08551d247
2025-11-21 09:05:50 +00:00
Jessica Lawshe 51639030f0 Merge pull request #29175 from overleaf/jel-new-user-domain-capture
[web] Managed users enrollment before user is created via domain capture

GitOrigin-RevId: af8ad32a9100413eb913372400bdb4a342d6710f
2025-11-21 09:05:45 +00:00
Andrew Rumble beb6f6d484 Merge pull request #29597 from overleaf/ar-last-features-esm-conversion
[web] last features esm conversion

GitOrigin-RevId: a35ab995bf654f1cdfe0e0062d8806761ecccf2d
2025-11-21 09:05:36 +00:00
David d56b80508b Merge pull request #29771 from overleaf/dp-beta
Give beta users back access to the editor redesign

GitOrigin-RevId: 11c3044c85cdfbd4bb3745cd0c575a8bc5af4ec2
2025-11-20 09:06:10 +00:00
Alf Eaton fc1563f78c Merge pull request #29747 from overleaf/ae-workbench-updates
Small updates to the AI Workbench UI

GitOrigin-RevId: 358bf65bd786c1cd6bd3cc352dea15890325176e
2025-11-20 09:06:05 +00:00
Mathias Jakobsen b9bad54dc6 Merge pull request #29604 from overleaf/mj-invite-to-group-missing-tag
[web] Add missing child tag group invitation inviter name

GitOrigin-RevId: a0367f821917b937cbe68cfbb8b5a5f5a189d8f8
2025-11-20 09:06:01 +00:00
Andrew Rumble 5a4592b153 Merge pull request #29720 from overleaf/renovate-npm-glob-vulnerability
[Core] Update dependency glob to v11.1.0 [SECURITY] - abandoned

GitOrigin-RevId: 866612e84e2afd3edc97c244e22faeaff22484cf
2025-11-20 09:05:44 +00:00
David e77a7cede7 Merge pull request #29745 from overleaf/dp-close-button-color
Fix product tour close button color in dark mode

GitOrigin-RevId: 8862b7414ee857497d37a313386229272eb6a28c
2025-11-20 09:05:39 +00:00
Miguel Serrano fb8d45d1f0 [CE/SP] Hotfix 5.5.7/6.0.1 (#29621)
Addresses docker configuration issues

Updates min mongo version checks in 6.0.1

GitOrigin-RevId: 7d799614520fb681f3641d47f2a6af3c2a09a1a8
2025-11-20 09:05:34 +00:00
David af41215058 Merge pull request #29607 from overleaf/dp-redesign-opt-in
Add opt-in for editor redesign

GitOrigin-RevId: 29ec8f4045a6bf29ab26a5ce5bceff70fb3aba6e
2025-11-20 09:05:28 +00:00
Kristina 42fa9701e5 Merge pull request #29714 from overleaf/kh-rm-dead-sessions-code
[web] remove dead code from Stripe hosted checkout

GitOrigin-RevId: 47372e320dbcee44e04b3bd731a585633433a5c8
2025-11-19 09:06:14 +00:00
Kristina 4e4c6010db [web] rm unused SetupIntentSucceededWebhookEvent (#29708)
GitOrigin-RevId: 9c8cd77c84be66c2032d89b3b4c65ce999c9ccbe
2025-11-19 09:06:09 +00:00
Jimmy Domagala-TangandDomagoj Kriskovic ff987aa433 Migration for "notificationsPreferences" collection (#29446)
* Implement notifications preferences model

* NotificationPreferences class

* remove index performance tests

* move to unit tests

* use zod

* saving multiple preference values

* set unique:true

* throw error if preferences can't be parsed

* use z.infer

* strict schema when saving preferences

* fix: update notifPreferenceKey type to only contain key values

---------

Co-authored-by: Domagoj Kriskovic <dom.kriskovic@overleaf.com>
GitOrigin-RevId: 20cf3799c91e6a890ab6217667594d181237c791
2025-11-19 09:06:01 +00:00
Mathias Jakobsen 06a1fc32ec Merge pull request #29679 from overleaf/mj-references-server-pro
[server-pro] Stop running references in server pro

GitOrigin-RevId: 41a9c3ca025bb3b631c3007c88f0fea6efbbe4fb
2025-11-19 09:05:52 +00:00
ilkin-overleaf e81ca06f9c Merge pull request #29614 from overleaf/ii-domain-capture-mu-email-check
[web] Check email from SAML callback before enrollment page

GitOrigin-RevId: 3c8224d42b87969290d5031a28d4ec217e875d84
2025-11-19 09:05:43 +00:00
ilkin-overleaf d65f5a416c Merge pull request #29273 from overleaf/ii-domain-capture-saml-provider-error-on-join
[web] SAML error messages on domain capture page

GitOrigin-RevId: 81f1fe6aafad45e95380cfa4e387d5b9bd04b49d
2025-11-19 09:05:39 +00:00
ilkin-overleaf 478df81f87 Merge pull request #29059 from overleaf/ii-domain-capture-saml-provider-error
[web] Saml request denied error

GitOrigin-RevId: 73cca9cbc5421bed141fbf0b4978d71930758824
2025-11-19 09:05:34 +00:00
Tim Down 983382f1f1 Initial implementation of unified access registration first page (#29559)
* Initial implementation of registration first page

* CSS tweaks from review

* Suppress skip-to-content link

* Fix formatting

* Make logo and footer bottom margin always appear in CIAM register page

* Fix font size and margin of card footer text

* Pug fixes from linter

* Fixes from merge of main

* Use translation string

GitOrigin-RevId: 0486532112d81462a008206e3f1a97c409d39a6a
2025-11-19 09:05:29 +00:00
Tim Down 41d120d8f1 Merge pull request #29038 from overleaf/td-eslint-e2e-tests
Enable ESLint for all end-to-end tests

GitOrigin-RevId: 5d085f52fabcc794b0457edbbb551500477d4110
2025-11-19 09:05:24 +00:00
Brian Gough 3227502aeb Merge pull request #29718 from overleaf/bg-history-fix-backup-errors
fix backupBlob error handling and add tests for upload failures

GitOrigin-RevId: 3abda1b70012fda20fc403593d0ee6ce04152e24
2025-11-19 09:05:19 +00:00
Mathias Jakobsen 7b331b0222 [web] Recreate workbench with Overleaf styles (#29651)
GitOrigin-RevId: 52ca336f70b29edf6e39cf95aa164f3ae32c0a79
2025-11-19 09:05:14 +00:00
Borja b1009d3b1f Writefull refactor bootstrapping (#29549)
GitOrigin-RevId: f8422d3c3d1d7e588f18352e08c7596b520225e5
2025-11-19 09:05:09 +00:00
Brian Gough b7015c1dfa Merge pull request #29717 from overleaf/ii-subscpriptions-v1-id-index-history-v1
[web] Fix failing acceptance tests in history-v1 and github-sync

GitOrigin-RevId: cae820598dfe7779386958fd759d3381b6007303
2025-11-18 09:06:18 +00:00
ilkin-overleaf 341b9b9e0b Merge pull request #29487 from overleaf/ii-subscpriptions-v1-id-index
[web] Update v1_id index to be unique

GitOrigin-RevId: 99ba8f10a1b34f7717f57cd5495d4159019343d1
2025-11-18 09:06:13 +00:00
ilkin-overleaf 9ea8031055 Merge pull request #29558 from overleaf/ii-domain-capture-admin-view-user-email-attribute
[web] Display user email attribute on the admin panel

GitOrigin-RevId: aaf08a01c8fec33960e904b3511a0170ea83c936
2025-11-18 09:06:09 +00:00
Brian Gough 581a3b7ce7 Merge pull request #29700 from overleaf/bg-history-v1-log-stalled-uploads
Add timeout warnings for long-running blob and chunk uploads

GitOrigin-RevId: 5a57ebaaea9dfcaf23153f7e6f27190af541eb16
2025-11-18 09:06:02 +00:00
Andrew Rumble 28f0b8be89 [web] Sanitize URLs to remove sensitive build IDs (#29486)
from overleaf/ar-bg-filter-buildids-from-sentry

GitOrigin-RevId: 66746bc0584fd75fa27a54ef1a666d5e7fa53fce
2025-11-18 09:05:57 +00:00
Andrew Rumble f306e1325e Add migration to drop docHistoryIndex
GitOrigin-RevId: 859b610313135338b6e6b58173b8980b057dc2a9
2025-11-18 09:05:53 +00:00
Andrew Rumble ee5ff397f8 Remove docHistoryIndex collection from db helpers
GitOrigin-RevId: 02a2c2291e1b7cb92558e2b1091275bd6cd15e5b
2025-11-18 09:05:49 +00:00
Andrew Rumble cc1eb9b6e5 Cleanup direct usages of docHistoryIndex
GitOrigin-RevId: 9de5cffae3e7be053af73013ea5ac0ee8202fc54
2025-11-18 09:05:45 +00:00
Antoine Clausse 0e4682ef89 [web] Create DSFormControl Input components (#29647)
* Create DS version for Bootstrap Input form elements

* Move DS Button Storybook to DS component folder

* Use phosphor icons

* Add ds-focus-outline mixin

* Use math.div

GitOrigin-RevId: e50934212ec5949f0f7abc7880eb73933fce2a9b
2025-11-18 09:05:34 +00:00
Antoine Clausse 1447842fbd Remove scripts about unconfirmed emails removal (#29683)
* Remove unconfirmed email deletion scripts

* Remove tests

GitOrigin-RevId: a0ef84207fced135a13074265fe5d3b38400d76f
2025-11-18 09:05:29 +00:00
John Lees-Miller 9408d253da Remove apparently unused files
GitOrigin-RevId: 60a4427c9c8a58ae700244f06d80c574002e923c
2025-11-18 09:05:25 +00:00
John Lees-Miller 0d71c825a9 Bump fake-gcs version and fix resumable uploads
GitOrigin-RevId: b1f3cf74f59ff53961665e19826b2f10ac235016
2025-11-18 09:05:21 +00:00
Andrew Rumble 799a346a13 [monorepo] script to find dependencies needing a major upgrade (#28886)
from overleaf/ar-find-outdated-dependencies-script

GitOrigin-RevId: 6981072d50d6e0ce5a4b13ade7e3d87a713c8d9f
2025-11-18 09:05:16 +00:00
Andrew Rumble 394c60f2cf Merge pull request #29659 from overleaf/revert-29656-revert-29521-ar-models-es-conversion
Revert "Revert "[web] Convert models and self-referential test files to ESM ""

GitOrigin-RevId: f64000ae31d298b075a8722dfc51f294c71bc021
2025-11-18 09:04:56 +00:00
Brian Gough f3d0c6920f Merge pull request #29692 from overleaf/dependabot-npm_and_yarn-js-yaml-4.1.1
Bump js-yaml from 4.1.0 to 4.1.1

GitOrigin-RevId: eaa7b5b0a6ddcd111f280d3ef122b8cdf0072ae5
2025-11-18 09:04:51 +00:00
Rebeka Dekany b773ac2715 Add focus trap to Modal component (#28754)
* Add focus-trap-react npm package

* Trap the focus for the Modal

* In some cases, the focus will not return to the trigger element

* If there are no tabbable elements, the focus should fallback

* Add explanations for focusTrapOptions props and extend test

* Auto generate package-lock.json - Add focus-trap-react npm package

GitOrigin-RevId: 488a05d5e95dd369c69bedcfaf7c1fd5e456e302
2025-11-17 09:05:45 +00:00
Kristina 198a2fc943 [web] limit trials to one per lifetime (#29682)
* limit trials to one per lifetime
* update warning on checkout

GitOrigin-RevId: 6c9ac771c8b8eaa2bd86bdb9e7f3931783388c0d
2025-11-17 09:05:40 +00:00
Davinder Singh cb9d8844fe adding a function to trim the staffAccess for subscription page (#29640)
GitOrigin-RevId: ee030df2fb7df19a1b719311772b454983c2394f
2025-11-17 09:05:32 +00:00
Kristina 3194434767 [web] display all Stripe accounts on admin panel (#29625)
* refactor PaymentService.getPaymentProviderAdminUrl to be more useful
* display all stripe customer accounts
* mv change segment modal to each account
* stripeSubscriptionData -> stripeCustomerData

GitOrigin-RevId: 4c1a277f5073ee7cb12f4596210ba4f8624451b8
2025-11-17 09:05:16 +00:00
Kristina 939efc7201 Merge pull request #29564 from overleaf/kh-add-stripe-info-to-front
[web] include Stripe customer dashboard link in Front

GitOrigin-RevId: 73a268426610e48a3211fa8e1e994428c84a79ef
2025-11-17 09:05:11 +00:00
Jimmy Domagala-Tang 5b8f6f83be Assume users are in enterprise commons if v1 affiliates lookup fails (#22728)
* updating affiliation check for enterprise commons to default to restricting wf on error

* feat: simplify logic on affiliate lookup failure

GitOrigin-RevId: ccd676af9a44413bf63fe7c1f7836080c2612f45
2025-11-14 09:05:58 +00:00
Liangjun Song 5730fb993a Merge pull request #29459 from overleaf/ls-support-stripe-subscription-when-accepting-group-invite
Support Stripe subscription when accepting group invite from managed group

GitOrigin-RevId: 8b374bd35926a3c074e20bbe45bd6625cc6ba99f
2025-11-14 09:05:50 +00:00
Eric Mc Sween a67d70c74a Merge pull request #29609 from overleaf/renovate-npm-nanoid-vulnerability
Update dependency nanoid to v5 from ^4.0.2 [SECURITY]

GitOrigin-RevId: 9d87781d2169fb1c9003d3c42b4531bb9e1c377e
2025-11-14 09:05:45 +00:00
Tim Down c0c3bfe185 DS button CSS and component implementation plus move most --ciam variables to --ds
GitOrigin-RevId: 5dd6b490a6f597892b47a89aabce748cea3e3bc6
2025-11-14 09:05:34 +00:00
Andrew Rumble ccf1fb8fcb Merge pull request #29662 from overleaf/ar-allow-esm-tests-to-be-grepped
[web] Split vitest tests and spread args

GitOrigin-RevId: d0e06836fc4f4b9de50def456aef7f0ecb6cb128
2025-11-14 09:05:29 +00:00
Thomas c059a3c5b0 Handle slashes in branch names for docker build tags (#29529)
* Refactor v1 Makefile to use DOCKER_COMPOSE variable for Docker commands with tag safe branch name

* Handle slashes in branch names for docker build tags

GitOrigin-RevId: 463940e8435845978aced745575905f3bfbb8e1c
2025-11-14 09:05:25 +00:00
Miguel Serrano 7d0e75e4f7 [web] Managed Group Audit Logs for project management (#29584)
GitOrigin-RevId: 8edf4e580c001db3129c276d23e90ce9e82ac2ea
2025-11-13 09:06:55 +00:00
Eric Mc Sween 44b79c895f Merge pull request #29655 from overleaf/em-record-replay-github-tests
Do not make real calls to GitHub during acceptance tests

GitOrigin-RevId: 83efaaa2a1abe960ecebf5e09288a4bcadf013e1
2025-11-13 09:06:46 +00:00
Andrew Rumble ae6dec9dcb Merge pull request #29656 from overleaf/revert-29521-ar-models-es-conversion
Revert "[web] Convert models and self-referential test files to ESM "

GitOrigin-RevId: 5455cccbb513bd9ca36ce526ff1553065f83d233
2025-11-13 09:06:36 +00:00
Brian Gough e7cc70baf7 Merge pull request #29639 from overleaf/bg-block-clone3-for-docker
use docker default seccomp rule for clone3

GitOrigin-RevId: 32a65a2f2262225fafa1ac1a9f8d6f2767c2829c
2025-11-13 09:06:28 +00:00
Brian Gough 67aa42a57a Merge pull request #29650 from overleaf/bg-update-clsi-tests-to-2025
update clsi acceptance tests to use texlive 2025.1 by default

GitOrigin-RevId: d69e97132e87873a8b91c39494c545250298d935
2025-11-13 09:06:23 +00:00
Brian Gough 4ca1407ab9 Merge pull request #29638 from overleaf/bg-add-shell-escape-tests-to-clsi
add shell escape tests to clsi

GitOrigin-RevId: 6cd3ab24fa76f74dccfec43bf6a3d06c0fe9ec6a
2025-11-13 09:06:18 +00:00
Andrew Rumble 7c9fea64ac [web] Convert models and self-referential test files to ESM (#29521)
from overleaf/ar-models-es-conversion

GitOrigin-RevId: a92ab8342c0f3e23155eacc0570458fc910c3d71
2025-11-13 09:06:13 +00:00
Malik Glossop 59aab0878d Merge pull request #29635 from overleaf/mg-project-actions-bp
Update projection action breakpoint for dropdown from md to lg

GitOrigin-RevId: 749f0abbdae6686959773ea6cfca22b488064451
2025-11-13 09:06:09 +00:00
David c4b3cd2a77 Merge pull request #29511 from overleaf/dp-new-users-to-new-editor
Move all new users to use the new editor

GitOrigin-RevId: e3611e5853da4b96db9f4cc37114ededb8632aed
2025-11-13 09:06:00 +00:00
Miguel Serrano 1479df36db [web] Managed Group Audit Logs for github/dropbox (#29582)
GitOrigin-RevId: 9c2db408734469f67eaca7f4b7f0ebc6babcfcd4
2025-11-13 09:05:55 +00:00
Antoine ClausseandTim Down f028f21e3c [web] Remove the nocdn fallback (#29311)
* Remove the nocdn fallback

Co-authored-by: Tim Down <tim.down@overleaf.com>

* Remove comment about nocdn query string in ExpressLocals.mjs

Co-authored-by: Tim Down <tim.down@overleaf.com>

* Remove `Frontend` global

---------

Co-authored-by: Tim Down <tim.down@overleaf.com>
GitOrigin-RevId: 74160ed4cf8ba17f8bd9b6793c8baa80883d3361
2025-11-12 09:05:31 +00:00
Malik Glossop 92a14715ec Merge pull request #29611 from overleaf/mag-rm-revert-file-tooltip
[web] remove revert file tooltip

GitOrigin-RevId: dafd6fc160ec1f252cbeb9e2f952184d9d829dc7
2025-11-12 09:05:27 +00:00
Malik Glossop 65419ad6f1 Merge pull request #29520 from overleaf/mag-tool-tip-casing
Update toolbar tooltips

GitOrigin-RevId: 80d3fa906776684275c856d1a74171d5b8a4f65a
2025-11-12 09:05:23 +00:00
Miguel Serrano fe884195dc [web] Add Project logs to Group Audit Logs view (#29456)
* Add `project-created` audit log only for managed users

* Include project audit logs in group audit logs

* Added details column in Group Audit Logs UI

GitOrigin-RevId: 96c7a31b37270912df1629e27d905b692f28da46
2025-11-12 09:05:18 +00:00
Brian Gough 43c1ad2b5a Merge pull request #29618 from overleaf/bg-allow-statx-call-in-clsi-seccomp
allow statx and openat2 syscalls in seccomp profile

GitOrigin-RevId: f7d3ae5bb5f2fedcc9e071d70f24baaf13be27f4
2025-11-12 09:05:08 +00:00
Jimmy Domagala-TangandAlf Eaton 61180224e1 updated copy for monthly TexLive labs experiment (#29168)
* feat: update copy for monthly tl labs experiment

* Apply suggestions from code review

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

---------

Co-authored-by: Alf Eaton <alf.eaton@overleaf.com>
GitOrigin-RevId: 808207deecd1c523e08eacd2f3cd07c92c713b59
2025-11-11 09:06:22 +00:00
Olzhas Askar 86b860ee32 Merge pull request #29569 from overleaf/oa-promocode-warnings
[web] Promocode warnings

GitOrigin-RevId: 020380e31c26d13e9b74b0f5df588942d302f8db
2025-11-11 09:06:17 +00:00
Mathias JakobsenandAlf Eaton 8024fe2c58 [web] Add AI workbench to alpha users (#29417)
Co-authored-by: Alf Eaton <alf.eaton@overleaf.com>
GitOrigin-RevId: 79bb329932b1e6fcc88f648bca9cc4bee215cd41
2025-11-11 09:06:08 +00:00
Domagoj Kriskovic c84cfc815a Document updater script for notifying web on project updates (#29490)
* Document updater script for notifying web on project updates

* use lua script for deleting keys

* define jobId when adding to queue

* removeOnFail age

* mongo check if collaborator exists

GitOrigin-RevId: f67a79c890a03ccf44fd84243c9a3f380e7afb43
2025-11-11 09:06:04 +00:00
Davinder Singh 34173eda46 Change subscription page title to "Your subscriptions" (#29377)
* adding plural translations for the languages that were easy to test with the help of AI

* adding remaining translations

* adding your_subscriptions

* running make sort_locales

* fixing nl.json to make it formal You

GitOrigin-RevId: 7510e2f8eee87fd2a256ece434cc59e6877893e6
2025-11-11 09:05:44 +00:00
Mathias Jakobsen 0110ac4715 [web] Convert LaTeX linter to Typescript (#29483)
GitOrigin-RevId: ec79e95db03bbea60da01eb8b35989978e1ec33a
2025-11-11 09:05:39 +00:00
David cd335419ff Merge pull request #29603 from overleaf/dp-detached-pdf-light
Fix missing light theme for detached pdf

GitOrigin-RevId: 61af7e34c44f6d2842ca9d5c1b5d7458a2a1a6c8
2025-11-11 09:05:34 +00:00
David 847fd4a432 Merge pull request #29538 from overleaf/dp-dark-divider
Fix DS nav dark border divider colors

GitOrigin-RevId: 72ad70d9f3a07abfc6f0e811609b655fb42b34ac
2025-11-11 09:05:29 +00:00
Davinder SinghandRebeka 6008f8b764 Replacing placeholders with labels for institution Role and department (#29425)
* removing placeholders and adding labels

* adding a test

* adding a test back

* deleting comment

* Target the label of department and role

---------

Co-authored-by: Rebeka <o.dekany@gmail.com>
GitOrigin-RevId: 890c2f836a17c360a577bd71280805e3e5408dd6
2025-11-11 09:05:25 +00:00
Anna Claire Fields 808b7bd92c Merge pull request #29533 from overleaf/acf-admin-role-for-sales-support
Add sales-support role with group-modify perms

GitOrigin-RevId: 4d145ed79cfcb4266494f0263bd5693eb4e20fc5
2025-11-10 09:05:23 +00:00
Gernot Schulz bed63fd954 Merge pull request #29586 from overleaf/gs-jenkins-pr-build-tags-git-br
Include commit look-up stage in git-bridge Jenkinsfile

GitOrigin-RevId: 993cabcafd057dc6767a2780c2dd11708482d536
2025-11-10 09:05:12 +00:00
roo hutton 386fa19ffc Merge pull request #29557 from overleaf/rh-compile-timeout-event-fix
Send paywall-click events when navigation suppressed

GitOrigin-RevId: b36dcb590d4d30a47a30f95febb4cf479c38f377
2025-11-10 09:05:04 +00:00
Gernot Schulz b834b8bcb7 Merge pull request #29537 from overleaf/gs-jenkins-pr-build-tags-templates
Tag images with branch head instead of merge commit (templates)

GitOrigin-RevId: 53e616aeec058863e25b356841a59f3ebe13c87f
2025-11-10 09:05:00 +00:00
Brian Gough b0d7728de3 Merge pull request #29546 from overleaf/mfb-from-joi-to-zod-real-time
RE MIGRATE from joi to zod, moving schemas to top level in file

GitOrigin-RevId: c1512be2e7d6edf52c3dc01d62f2fc2051b3d9b2
2025-11-07 09:05:46 +00:00
Andrew Rumble 0cc7bb0fd7 Update makefile and Jenkins job to run test projects separately
GitOrigin-RevId: b1fbae22be53904128245e171d5b8a674697710b
2025-11-07 09:05:34 +00:00
Andrew Rumble 1361bc2858 Split test projects so we can apply --no-file-parallelism
GitOrigin-RevId: 37f11a9e363bcf91dd77f62ef191f62d61e3a94f
2025-11-07 09:05:29 +00:00
roo hutton d2cf8d58cf Merge pull request #29528 from overleaf/rh-ai-modal-logos
Remove brand logos and tweak copy in AI assist modal

GitOrigin-RevId: 07b13d21b312b9098543e42fbc93a568929f4c67
2025-11-07 09:05:21 +00:00
Antoine Clausse f2788868ac [web] Create script to re-add wrongly deleted emails (#29550)
* Allow passing auditLog extra info in addEmailAddress

* Create script re_add_deleted_emails.mjs

* Check email validity when parsing the CSV

* Allow no IP and initiator for the log events

* Add an acceptance test on re_add_deleted_emails

* Fix remove_unconfirmed_emails.mjs

We're not planning to run this again, but this could help if some code from here ever gets copy-pasted

* Fix remove_unconfirmed_emails.mjs

Rename `emailsToRemove` to `emailsToRemoveCandidates`

* Remove console.logs of event logs:

That's unnecessary complexity and we already have the data from the previous script

* Copy `addEmailAddress` into the script

* Handle primary emails correctly

* Ignore a TS error

* Fix async function in createUsers (tests)

* Add assertion for already in use emails in ReAddDeletedEmailsTests

* Add information in admin-panel for add-email audit logs

GitOrigin-RevId: f8480426d7b323f88a268874488d9ae641bc6045
2025-11-07 09:05:17 +00:00
Gernot Schulz 05844b8e08 Merge pull request #29540 from overleaf/gs-jenkins-pr-build-tags-remote
Check if Jenkins checkout revision exists on remote

GitOrigin-RevId: cb110f5479836ccbfd1a62f501210dee6606d37e
2025-11-06 09:07:23 +00:00
Borja 7f96e9504e Revert "Writefull refactor bootstrapping (#29306)" (#29542)
This reverts commit 6de05eb695579dc08cb5ee6ddf30c243cc2ff86a.

GitOrigin-RevId: 1fe00bd95b2ce437f91b38667e4d787d49c36902
2025-11-06 09:07:14 +00:00
Andrew Rumble f5eb8e9ba4 Update paths
GitOrigin-RevId: 5bc9bccf2cd10631cb88412f426a8e3c73c9f689
2025-11-06 09:07:09 +00:00
Andrew Rumble 5914c9ff09 Update paths
GitOrigin-RevId: 298e3de065fbab3703e90a3d56a89c448fe164e2
2025-11-06 09:06:57 +00:00
Andrew Rumble b5216af8f7 Convert to ESM
GitOrigin-RevId: 097bc45d500b4d2538ee49d60a597619579419a5
2025-11-06 09:06:52 +00:00
Andrew Rumble ed966e1392 Rename files
GitOrigin-RevId: 1cb1e8929018da4cdc0cf01746511fd6e4243a1b
2025-11-06 09:06:47 +00:00
Antoine ClausseandCopilot 25993cb858 [web] Add script to check for wrongly removed confirmed emails (#29532)
* [web] Add script to check for wrongly removed confirmed emails

* List emails that were added again

* Use `trackProgress`

* Prettier logs

* Add `READ_PREFERENCE_SECONDARY`

* Check `change-primary-email`

* Add check with `confirm-email` should be always empty, but let's check

* Update services/web/scripts/check_removed_emails.mjs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
GitOrigin-RevId: 4f83d69cffd0aec2c5d1201f1f6130eacdbb2e39
2025-11-06 09:06:42 +00:00
David fd96baaf05 Merge pull request #29536 from overleaf/dp-fix-logo
Fix overleaf logo color on ds nav

GitOrigin-RevId: c48ed09339aa1af03bdbad29e76d8cdb74260f0c
2025-11-06 09:06:37 +00:00
roo hutton 2e11f2c7b7 Merge pull request #29394 from overleaf/rh-compile-timeout-modal
Add compile timeout modal for compile-timeout-target-plans test

GitOrigin-RevId: b352cb239742aa7ffbef7f3cd5c65ac719569ebf
2025-11-06 09:06:29 +00:00
David faceb90593 Merge pull request #29290 from overleaf/dp-dashboard-dark-2
Dark mode for DS nav

GitOrigin-RevId: fb8ad9ec45e88c39810421d11ecc69ab874121ce
2025-11-06 09:06:24 +00:00
Brian Gough d10cdb96b3 Merge pull request #29530 from overleaf/revert-29472-mfb-from-joi-to-zod-real-time
Revert "Mfb from joi to zod real time"

GitOrigin-RevId: 3bb8b01c692083c1b15d8a53066c01f0ec7af8f6
2025-11-06 09:06:19 +00:00
Andrew Rumble da91e15aa0 Export everything from PaymentProviderEntities
This improves the type inference in modules that check the types.

GitOrigin-RevId: c8ffc1f7c04fbbc097758b1bc1e63ea33e52d3ba
2025-11-06 09:06:14 +00:00
Andrew Rumble c7c15b2066 Split tests into sequential and parallel projects
Sequential tests need to be run without parallelism because they rely on
a database fixture that can have side effects.

GitOrigin-RevId: b614cbe4dbaf2319e681d5607a0a64cbbed8c021
2025-11-06 09:06:06 +00:00
Andrew Rumble 4f02a85aa4 Update paths
GitOrigin-RevId: 399c594dd1bbf739d91874df6be3b70e57fe01e3
2025-11-06 09:05:57 +00:00
Andrew Rumble 93b7274ea6 Convert tests to ESM
GitOrigin-RevId: 03bd4db8cddc548706439edd7f6db0bc3e7ed9d3
2025-11-06 09:05:51 +00:00
Andrew Rumble 912324f560 Convert to ESM
GitOrigin-RevId: b58b02f9e9c8d47909e95c3ade8e1bf33ed46c80
2025-11-06 09:05:47 +00:00
Andrew Rumble 0f4d5a7be6 Rename files
GitOrigin-RevId: 80b975b03ebca16328b84fabf11e71bbea87c8bc
2025-11-06 09:05:41 +00:00
Borja 1a511b14a4 Writefull refactor bootstrapping (#29306)
GitOrigin-RevId: 6de05eb695579dc08cb5ee6ddf30c243cc2ff86a
2025-11-05 09:07:09 +00:00
Maria Florencia Besteiro Gonzalez 820ce8ad1c Merge pull request #29472 from overleaf/mfb-from-joi-to-zod-real-time
Mfb from joi to zod real time

GitOrigin-RevId: 657c18bae01eaeea76bf308579a7bea1388253d6
2025-11-05 09:07:04 +00:00
Jakob Ackermann 3586b37491 [web] Remove clsi-cache-prompt/survey, split-tests and events (#29510)
* [web] Remove clsi-cache-prompt/survey and split-tests

* [web] Remove initial 50/50 clsi-cache split-test

* [web] Remove synctex-downloaded-from-cache event

* [web] Remove fallback-to-clsi-cache event

* [saas-e2e] fix tests with clsi-cache enabled

GitOrigin-RevId: b5cf2ab073dc866fe398b81fd5afe46422134c80
2025-11-05 09:06:59 +00:00
David 6aa9e5c855 Merge pull request #29496 from overleaf/dp-remove-new-editor-old-logs
Move all new editor users to new logs

GitOrigin-RevId: 224a4476eddb6576eaa04086a68b6579650a1bc5
2025-11-05 09:06:50 +00:00
David d48518e01d Merge pull request #29495 from overleaf/dp-remove-new-logs-position
Remove error logs from new editor rail

GitOrigin-RevId: 9d0b134345b63618334c5507089debf2df104274
2025-11-05 09:06:45 +00:00
Jakob Ackermann 5140fff347 [clsi] gracefully handle fast exit of synctex/wordcount containers (#29505)
* [clsi] gracefully handle fast exit of synctex/wordcount containers

* [clsi] do not change container options in-place for logging

GitOrigin-RevId: 0b685310a3c72f8f46125fefaa30c1ddb19e7b07
2025-11-05 09:06:40 +00:00
Jakob Ackermann 6691c5dc05 [monorepo] enable mongo notablescan for all services but web (#29497)
* [migrations] make old migrations compatible with --notablescan in mongo

Re-running the migration for db.users.emails.reversedHostname on all
Server Pro/CE users will not be harmfull.

* [monorepo] enable mongo notablescan for all services but web

GitOrigin-RevId: e2a710c9de08de9ac2aa9df1f3082d5f1c33ea05
2025-11-05 09:06:35 +00:00
Antoine Clausse 2ebc411db4 [web] Create a first implementation of the CIAM version of the email confirmation page (#29432)
* Move `main#main-content.content.content-alt` into a React component (`ContentLayout`)

* Create the CIAM variant of `RegistrationConfirmEmailForm`

* `bin/run web npm run extract-translations`

* Use `CiamLayout` in the Storybook demo

* Add `SplitTestProvider` in tests

* Fix Storybook: Wrap `RegistrationConfirmEmailForm` Story in `onboarding-confirm-email`

* Refactor SCSS files:

- only imports in all.scss
- split .storybook-layout and .storybook-enabled
- extract ciam-spacing.scss

GitOrigin-RevId: f4a214a0978423a1621dd8f60bf459af7b8f877e
2025-11-05 09:06:30 +00:00
Miguel Serrano a4d9d5789a [web] Add User logs to Group Audit Logs view (#29480)
* Revert "Revert "[web] Add User logs to Group Audit Logs view (#29155)" (#29479)"

This reverts commit 40a1516ab9cec690d0487a0a870b9fab17598d60.

* Fix `managedUsersEnabled` flag in frontend

GitOrigin-RevId: ae3edf5bcbc01ec46bc18028e758d3364072c307
2025-11-05 09:06:25 +00:00
Jakob Ackermann 78d7178c08 [web] fix gallery templates e2e tests (#29508)
GitOrigin-RevId: ba8a1ddfd56b3221db92e2869e0852fd4c7a4348
2025-11-05 09:06:20 +00:00
Miguel Serrano 6ca1a9e472 [git-bridge] Update dependency versions (#29484)
GitOrigin-RevId: 1640ea71798f650196f20f656f8656f3abeee7e5
2025-11-04 09:06:15 +00:00
Maria Florencia Besteiro Gonzalez 8cd2f6ac46 Merge pull request #29485 from overleaf/mfb-from-joi-to-zod-clsi-cache-revert
Reapply "migrate from joi to zod CLSI-CACHE service"

GitOrigin-RevId: 638b9e21b8cf18c1733f8a01375dab4099fe5d73
2025-11-04 09:06:10 +00:00
Alf Eaton c3881084be Merge pull request #29444 from overleaf/ds-remove-brazil-discount-banner
Removing GEO Price Banner from Brazil

GitOrigin-RevId: 85968cb546083bb3d3a526061daf8e6c1149867d
2025-11-04 09:06:06 +00:00
Alf Eaton 1d3d81e67d Allow enabling EditContext in CodeMirror (#29114)
GitOrigin-RevId: 15d70fd2d5da68d43f441bb0c65ff0cd2d785306
2025-11-04 09:06:01 +00:00
Alf Eaton ad3d68ece0 Record when the word count modal is opened (#29134)
GitOrigin-RevId: d49778199e793297c49447f56060dedb31750c34
2025-11-04 09:05:57 +00:00
Alf Eaton 632f7c85ed Remove content class names from token access page (#29212)
GitOrigin-RevId: 6e3e8ab9b445eed698f6d019841d12cfc24d0454
2025-11-04 09:05:52 +00:00
Miguel Serrano 1a3ce3f192 Revert "[web] Add User logs to Group Audit Logs view (#29155)" (#29479)
This reverts commit c455edc5a700ba24e73a16b2a66b50cb92f24176.

GitOrigin-RevId: 40a1516ab9cec690d0487a0a870b9fab17598d60
2025-11-04 09:05:47 +00:00
Miguel Serrano 3522923d4e [web] Add User logs to Group Audit Logs view (#29155)
* [web] Add User logs to Group Audit Logs view

GitOrigin-RevId: c455edc5a700ba24e73a16b2a66b50cb92f24176
2025-11-04 09:05:35 +00:00
Borja 85848b927e fix: improve regex escaping in HighlightSearchTerm component (#29477)
GitOrigin-RevId: ceb9c461a22b0170d6275ff31247e0eab6b22197
2025-11-04 09:05:23 +00:00
Jimmy Domagala-Tang 42a80a1ca3 feat: moving to grouping by primarily recipient, then by project
GitOrigin-RevId: 31e3420d6f5834a9da405eea99f2f353a39a0f11
2025-11-04 09:05:19 +00:00
Jimmy Domagala-Tang 618445722a fix: renaming consts for min and max notification age
GitOrigin-RevId: 7d36d073301ff02d79e2296af7bfc946ea1ad72a
2025-11-04 09:05:14 +00:00
Jimmy Domagala-Tang d77be2c94e adding test for processNotifications
GitOrigin-RevId: 35825755344e9cc10f9e571a253a2eae982b306a
2025-11-04 09:05:10 +00:00
Jimmy Domagala-Tang bfa70bf43b feat: handle determining delay and when to send at notification processing instead of managing scheduledAt. this removes the need for scheduledAt as we will do the scheduling calculations at processing time
GitOrigin-RevId: d0bbd5adc29ab58a797c171b55aabfda1cec39ea
2025-11-04 09:05:05 +00:00
Domagoj Kriskovic 23fc714d93 Replace dependency on "mmmagic" (#29272)
* Replace dependency on "mmmagic"

* Refactor file type checks in OpenInOverleafHelper

GitOrigin-RevId: fc5876b75955cb4981f084df777caa294907c8f9
2025-11-04 09:05:00 +00:00
Borja b1b638dd90 Add modal to request language (#29441)
GitOrigin-RevId: a928f6c1eb12f1e47fc6f295b8cbb5c8740df5ac
2025-11-03 09:06:21 +00:00
Maria Florencia Besteiro Gonzalez a88c307962 Merge pull request #29471 from overleaf/revert-29369-mfb-from-joi-to-zod-clsi-cache
Revert "migrate from joi to zod CLSI-CACHE service"

GitOrigin-RevId: 1846e5a1d990f7ff22982fc32277e24d69e9d1e0
2025-11-03 09:06:10 +00:00
Maria Florencia Besteiro Gonzalez 1720314726 Merge pull request #29369 from overleaf/mfb-from-joi-to-zod-clsi-cache
migrate from joi to zod CLSI-CACHE service

GitOrigin-RevId: b583431a902a1183235cb91a270f4123a5a7e547
2025-11-03 09:06:05 +00:00
Antoine Clausse 5a242cd4ac [web] Add font Inter (#29440)
* Add font Inter

Files downloaded from https://rsms.me/inter/
Kept only the woff2 files and CSS definitions for Inter-Regular and Inter-SemiBold

* Delete inter folder

* Add inter to build-fonts.mjs and run it

* Add inter.css

* Update latofonts archive URL

GitOrigin-RevId: 24cd8a48f4566d8a55443eb2cd938ee129dff5f8
2025-11-03 09:05:57 +00:00
Antoine Clausse 4d1e316bea [web] Conditionally render copies of login/register pages (Pug) depending of a uniaccessphase1 split-test (#29390)
* Conditionally render a CIAM copy of login.pug depending on `ciam` split-test

* Conditionally render a CIAM copy of register.pug depending on `ciam` split-test

* Conditionally render a CIAM copy of institutional_login.pug depending on `ciam` split-test

* Rename the test to `uniaccessphase1`

* Fixup ciam paths (underscores, not hyphens)

* Escape translations in `log_in_with_existing_institution_email`

See https://github.com/overleaf/internal/pull/29390#discussion_r2479318609

GitOrigin-RevId: fff0e154d1e1faad4842a2c49fa5889f9cc189e6
2025-11-03 09:05:53 +00:00
Rebeka Dekany ec5a283e9e Handle autoplay failures by showing video controls (#29412)
GitOrigin-RevId: afe5d70d00bfda97cde7e3479875b9cd7be5c46f
2025-11-03 09:05:49 +00:00
Thomas c48bc282f1 Merge pull request #29066 from overleaf/copilot/fix-broken-links-manage-users
Hide Members tab for non-group subscriptions in admin panel

GitOrigin-RevId: 138566a6e3d89d3009d1b6683cbe04212d279969
2025-11-03 09:05:34 +00:00
Jakob Ackermann a80b69abe5 [web] move free compiles up one bracket (#29411)
GitOrigin-RevId: 613b703d677d91110cd6dcf085e9291008e05f5c
2025-11-03 09:05:23 +00:00
Simon Gardner 41976072e5 Update UX copy for group member management options
GitOrigin-RevId: 33fcc1da1fae77f57ca4833cbaf314f497ef0ab7
2025-11-03 09:05:11 +00:00
Jakob Ackermann 3a206074f2 [web] move premium compiles up one bracket (#29410)
GitOrigin-RevId: 53423f855b2c215f6cc926b480422b2ce3477a74
2025-10-31 09:06:32 +00:00
Mathias Jakobsen 046e74a2c6 Merge pull request #29443 from overleaf/mj-mobile-navbar-bg
[web] Restore transparent background for hamburger navbar items on mobile

GitOrigin-RevId: ce3a095ded307427f2175d7db2a562c106e4b2e9
2025-10-31 09:06:18 +00:00
1849 changed files with 70686 additions and 59134 deletions
+31 -33
View File
@@ -6,58 +6,52 @@
<h4 align="center">An open-source online real-time collaborative LaTeX editor.</h4>
<p align="center">
<a href="https://github.com/yu-i-i/overleaf-cep/wiki">Wiki</a> •
<a href="https://github.com/overleaf/overleaf/wiki">Wiki</a> •
<a href="https://www.overleaf.com/for/enterprises">Server Pro</a> •
<a href="#contributing">Contributing</a> •
<a href="https://mailchi.mp/overleaf.com/community-edition-and-server-pro">Mailing List</a> •
<a href="#authors">Authors</a> •
<a href="#license">License</a>
</p>
<img src="doc/screenshot.png" alt="A screenshot of a project being edited in Overleaf Extended Community Edition">
<img src="doc/screenshot.png" alt="A screenshot of a project being edited in Overleaf Community Edition">
<p align="center">
Figure 1: A screenshot of a project being edited in Overleaf Extended Community Edition.
Figure 1: A screenshot of a project being edited in Overleaf Community Edition.
</p>
## Community Edition
[Overleaf](https://www.overleaf.com) is an open-source online real-time collaborative LaTeX editor. Overleaf runs a hosted version at [www.overleaf.com](https://www.overleaf.com), but you can also run your own local version, and contribute to the development of Overleaf.
## Extended Community Edition
The present "extended" version of Overleaf CE includes:
- Template Gallery
- Sandboxed Compiles with TeX Live image selection
- LDAP authentication
- SAML authentication
- OpenID Connect authentication
- Real-time track changes and comments
- Autocomplete of reference keys
- Symbol Palette
- "From External URL" feature
[Overleaf](https://www.overleaf.com) is an open-source online real-time collaborative LaTeX editor. We run a hosted version at [www.overleaf.com](https://www.overleaf.com), but you can also run your own local version, and contribute to the development of Overleaf.
> [!CAUTION]
> Overleaf Community Edition is intended for use in environments where **all** users are trusted. Community Edition is **not** appropriate for scenarios where isolation of users is required due to Sandbox Compiles not being available. When not using Sandboxed Compiles, users have full read and write access to the `sharelatex` container resources (filesystem, network, environment variables) when running LaTeX compiles.
Therefore, in any environment where not all users can be fully trusted, it is strongly recommended to enable the Sandboxed Compiles feature available in the Extended Community Edition.
> Overleaf Community Edition is intended for use in environments where **all** users are trusted. Community Edition is **not** appropriate for scenarios where isolation of users is required due to Sandbox Compiles not being available. When not using Sandboxed Compiles, users have full read and write access to the `sharelatex` container resources (filesystem, network, environment variables) when running LaTeX compiles.
For more information on Sandbox Compiles check out Overleaf [documentation](https://docs.overleaf.com/on-premises/configuration/overleaf-toolkit/server-pro-only-configuration/sandboxed-compiles).
For more information on Sandbox Compiles check out our [documentation](https://docs.overleaf.com/on-premises/configuration/overleaf-toolkit/server-pro-only-configuration/sandboxed-compiles).
## Enterprise
If you want help installing and maintaining Overleaf in your lab or workplace, Overleaf offers an officially supported version called [Overleaf Server Pro](https://www.overleaf.com/for/enterprises).
If you want help installing and maintaining Overleaf in your lab or workplace, we offer an officially supported version called [Overleaf Server Pro](https://www.overleaf.com/for/enterprises). It also includes more features for security (SSO with LDAP or SAML), administration and collaboration (e.g. tracked changes). [Find out more!](https://www.overleaf.com/for/enterprises)
## Keeping up to date
Sign up to the [mailing list](https://mailchi.mp/overleaf.com/community-edition-and-server-pro) to get updates on Overleaf releases and development.
## Installation
Detailed installation instructions can be found in the [Overleaf Toolkit](https://github.com/overleaf/toolkit/).
Configuration details and release history for the Extended Community Edition can be found on the [Extended CE Wiki Page](https://github.com/yu-i-i/overleaf-cep/wiki).
We have detailed installation instructions in the [Overleaf Toolkit](https://github.com/overleaf/toolkit/).
## Upgrading
If you are upgrading from a previous version of Overleaf, please see the [Release Notes section on the Wiki](https://github.com/overleaf/overleaf/wiki#release-notes) for all of the versions between your current version and the version you are upgrading to.
## Overleaf Docker Image
This repo contains two dockerfiles, [`Dockerfile-base`](server-ce/Dockerfile-base), which builds the
`sharelatex/sharelatex-base:ext-ce` image, and [`Dockerfile`](server-ce/Dockerfile) which builds the
`sharelatex/sharelatex:ext-ce` image.
`sharelatex/sharelatex-base` image, and [`Dockerfile`](server-ce/Dockerfile) which builds the
`sharelatex/sharelatex` (or "community") image.
The Base image generally contains the basic dependencies like `wget`, plus `texlive`.
This is split out because it's a pretty heavy set of
We split this out because it's a pretty heavy set of
dependencies, and it's nice to not have to rebuild all of that every time.
The `sharelatex/sharelatex` image extends the base image and adds the actual Overleaf code
@@ -65,16 +59,20 @@ and services.
Use `make build-base` and `make build-community` from `server-ce/` to build these images.
The [Phusion base-image](https://github.com/phusion/baseimage-docker)
(which is extended by the `base` image) provides a VM-like container
We use the [Phusion base-image](https://github.com/phusion/baseimage-docker)
(which is extended by our `base` image) to provide us with a VM-like container
in which to run the Overleaf services. Baseimage uses the `runit` service
manager to manage services, and init scripts from the `server-ce/runit`
folder are added.
manager to manage services, and we add our init-scripts from the `server-ce/runit`
folder.
## Contributing
Please see the [CONTRIBUTING](CONTRIBUTING.md) file for information on contributing to the development of Overleaf.
## Authors
[The Overleaf Team](https://www.overleaf.com/about)
[yu-i-i](https://github.com/yu-i-i/overleaf-cep) — Extensions for CE unless otherwise noted
[The Overleaf Team](https://www.overleaf.com/about)
## License
-2
View File
@@ -77,10 +77,8 @@ each service:
| `filestore` | 9235 |
| `notifications` | 9236 |
| `real-time` | 9237 |
| `references` | 9238 |
| `history-v1` | 9239 |
| `project-history` | 9240 |
| `linked-url-proxy` | 9241 |
To attach to a service using Chrome's _remote debugging_, go to
<chrome://inspect/> and make sure _Discover network targets_ is checked. Next
-2
View File
@@ -7,7 +7,6 @@ FILESTORE_HOST=filestore
GRACEFUL_SHUTDOWN_DELAY_SECONDS=0
HISTORY_V1_HOST=history-v1
HISTORY_REDIS_HOST=redis
LINKED_URL_PROXY_HOST=linked-url-proxy
LISTEN_ADDRESS=0.0.0.0
MONGO_HOST=mongo
MONGO_URL=mongodb://mongo/sharelatex?directConnection=true
@@ -17,7 +16,6 @@ QUEUES_REDIS_HOST=redis
DSMP_REDIS_HOST=redis
REALTIME_HOST=real-time
REDIS_HOST=redis
REFERENCES_HOST=references
SESSION_SECRET=foo
V1_HISTORY_HOST=history-v1
WEBPACK_HOST=webpack
-22
View File
@@ -79,17 +79,6 @@ services:
- ../services/history-v1/knexfile.js:/overleaf/services/history-v1/knexfile.js
- ../services/history-v1/migrations:/overleaf/services/history-v1/migrations
linked-url-proxy:
command: ["node", "--watch", "app.mjs"]
environment:
- NODE_OPTIONS=--inspect=0.0.0.0:9229
ports:
- "127.0.0.1:9241:9229"
volumes:
- ../services/linked-url-proxy/app:/overleaf/services/linked-url-proxy/app
- ../services/linked-url-proxy/config:/overleaf/services/linked-url-proxy/config
- ../services/linked-url-proxy/app.js:/overleaf/services/linked-url-proxy/app.js
notifications:
command: ["node", "--watch", "app.ts"]
environment:
@@ -123,17 +112,6 @@ services:
- ../services/real-time/app.js:/overleaf/services/real-time/app.js
- ../services/real-time/config:/overleaf/services/real-time/config
references:
command: ["node", "--watch", "app.js"]
environment:
- NODE_OPTIONS=--inspect=0.0.0.0:9229
ports:
- "127.0.0.1:9238:9229"
volumes:
- ../services/references/app:/overleaf/services/references/app
- ../services/references/config:/overleaf/services/references/config
- ../services/references/app.js:/overleaf/services/references/app.js
web:
command: ["node", "--watch", "app.mjs", "--watch-locales"]
environment:
+1 -17
View File
@@ -86,13 +86,6 @@ services:
volumes:
- history-v1-buckets:/buckets
linked-url-proxy:
build:
context: ..
dockerfile: services/linked-url-proxy/Dockerfile
env_file:
- dev.env
mongo:
image: mongo:6.0
command: --replSet overleaf
@@ -129,7 +122,7 @@ services:
dockerfile: services/real-time/Dockerfile
env_file:
- dev.env
redis:
image: redis:5
ports:
@@ -137,13 +130,6 @@ services:
volumes:
- redis-data:/data
references:
build:
context: ..
dockerfile: services/references/Dockerfile
env_file:
- dev.env
web:
build:
context: ..
@@ -171,11 +157,9 @@ services:
- document-updater
- filestore
- history-v1
- linked-url-proxy
- notifications
- project-history
- real-time
- references
webpack:
build:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 587 KiB

@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/access-token-encryptor/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/access-token-encryptor/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/access-token-encryptor monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/access-token-encryptor/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'access-token-encryptor-eslint', name: 'access-token-encryptor eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/access-token-encryptor/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/access-token-encryptor monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/access-token-encryptor monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/access-token-encryptor monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'access-token-encryptor test results', testResults: 'libraries/access-token-encryptor/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/access-token-encryptor/reports'
sh 'make clean_jenkins -j10'
}
}
}
@@ -5,4 +5,5 @@ access-token-encryptor
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🚉 Platform
--public-repo=False
@@ -4,5 +4,6 @@ module.exports = {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
output: true,
},
}
+11
View File
@@ -0,0 +1,11 @@
module.exports = {
rules: {
'no-unnecessary-trans': require('./no-unnecessary-trans'),
'prefer-kebab-url': require('./prefer-kebab-url'),
'should-unescape-trans': require('./should-unescape-trans'),
'no-generated-editor-themes': require('./no-generated-editor-themes'),
'require-script-runner': require('./require-script-runner'),
'require-vi-doMock-valid-path': require('./require-vi-doMock-valid-path'),
'require-loading-label': require('./require-loading-label'),
},
}
@@ -0,0 +1,21 @@
module.exports = {
meta: {
type: 'error',
docs: {
description:
'Prohibit CodeMirror themes that are generated in a function',
},
},
create(context) {
return {
':matches(ArrowFunctionExpression, FunctionDeclaration, FunctionExpression) CallExpression > MemberExpression[object.name="EditorView"]:matches([property.name="theme"],[property.name="baseTheme"])'(
node
) {
context.report({
node,
message: `EditorView.theme and EditorView.baseTheme each add CSS to the page for every instance of the theme. Store the theme in a variable and reuse it instead.`,
})
},
}
},
}
@@ -0,0 +1,43 @@
module.exports = {
meta: {
type: 'problem',
fixable: 'code',
docs: {
description: 'Prohibit Trans with no components or values',
},
},
create(context) {
return {
'JSXOpeningElement[name.name="Trans"]'(node) {
const attributes = new Map(
node.attributes.map(attr => [attr.name.name, attr])
)
if (!attributes.has('components')) {
if (node.parent.children.length > 0) {
context.report({
node,
message: `Trans components must not have child elements`,
})
} else if (attributes.has('values')) {
context.report({
node,
message: `Use t('…') when there are no components`,
})
} else {
context.report({
node,
message: `Use t('…') when there are no components`,
fix(fixer) {
const i18nKey = attributes.get('i18nKey').value.value
// Note: Prettier can fix indentation
return fixer.replaceText(node.parent, `{t('${i18nKey}')}`)
},
})
}
}
},
}
},
}
+17
View File
@@ -0,0 +1,17 @@
{
"name": "@overleaf/eslint-plugin",
"version": "0.1.0",
"author": "Overleaf (https://www.overleaf.com)",
"license": "AGPL-3.0-only",
"main": "index.js",
"dependencies": {
"eslint": "^8.51.0",
"lodash": "^4.17.21"
},
"devDependencies": {
"@typescript-eslint/parser": "^8.50.0"
},
"scripts": {
"test": "node rules.test.js"
}
}
@@ -0,0 +1,83 @@
// URL parts should be kebab-case, but we didn't have this rule in the past.
// The ESLint rule `prefer-kebab-url` will ignore these "legacy" URL parts.
const ignoreWords = {
snake: new Set([
'clear_saml_data',
'confirm_link',
'confirm_university_domain',
'create_recurly_account',
'current_history_content',
'current_user',
'default_email',
'disable_managed_users',
'doc_snapshot',
'enable_history_ranges_support',
'features_override',
'generate_password_reset_url',
'get_assignment',
'get_clone',
'health_check',
'institutional_emails',
'latest_template',
'link_after_saml_response',
'linked_file',
'metrics_segmentation',
'new_users',
'no_autostart_post_gateway',
'personal_info',
'planned_maintenance',
'refresh_features',
'register_admin',
'register_ldap_admin',
'register_saml_admin',
'restore_file',
'revert_file',
'saved_vers',
'send_test_email',
'session_maintenance',
'set_in_session',
'sign_in_to_link',
'split_test',
'sso_configuration_test',
'sso_email',
'sso_enrollment',
'track_changes',
'update_admin',
'user_details',
]),
camel: new Set([
'addWorkflowScope',
'aiErrorAssistant',
'beginAuth',
'brandVariationId',
'closeEditor',
'completeRegistration',
'deactivateOldProjects',
'deletedSubscription',
'disconnectAllUsers',
'editingSession',
'emailSubscription',
'enableManagedUsers',
'externalCollaboration',
'flushProjectToTpds',
'indexAll',
'offboardManagedUser',
'openEditor',
'perfTest',
'pollDropboxForUser',
'resendInvite',
'resendManagedUserInvite',
'salesContactForm',
'showSupport',
]),
other: new Set([
'Project',
'disableSSO',
'enableSSO',
'resendSSOLinkInvite',
'usersCSV',
]),
}
module.exports = { ignoreWords }
@@ -0,0 +1,91 @@
const _ = require('lodash')
const { ignoreWords } = require('./prefer-kebab-url-ignore')
const removeTextBetweenBrackets = text => {
while (text.includes('[') || text.includes('(')) {
text = text.replaceAll(/\[[^[\]]*]/g, '')
text = text.replaceAll(/\([^()]*\)/g, '')
}
return text
}
const shouldIgnoreWord = str =>
str.includes(':') ||
str.includes('(') ||
str === '*' ||
str.match(/^[a-z0-9.]+$/) ||
ignoreWords.snake.has(str) ||
ignoreWords.camel.has(str) ||
ignoreWords.other.has(str)
const getSuggestion = routePath => {
if (typeof routePath === 'string') {
const kebabed = routePath
.split('/')
.map(word => (shouldIgnoreWord(word) ? word : _.kebabCase(word)))
.join('/')
return kebabed === routePath ? null : `'${kebabed}'`
}
if (routePath instanceof RegExp) {
const words = removeTextBetweenBrackets(routePath.source).match(/[\w-]+/g)
if (!words) return routePath
let newSource = routePath.source
for (const word of words) {
if (!shouldIgnoreWord(word)) {
newSource = newSource.replaceAll(
new RegExp(`\\b${word}\\b`, 'g'),
_.kebabCase(word)
)
}
}
const kebabed = new RegExp(newSource, routePath.flags)
return kebabed.source.toString() === routePath.source.toString()
? null
: kebabed
}
}
module.exports = {
meta: {
type: 'problem',
fixable: 'code',
hasSuggestions: true,
docs: {
description: 'Enforce using kebab-case for URL paths',
},
},
create: context => ({
CallExpression(node) {
if (
node.callee.type === 'MemberExpression' &&
node.arguments[0]?.type === 'Literal' &&
[/app/i, /router/i].some(callee =>
typeof callee === 'string'
? node.callee.object.name === callee
: callee.test(node.callee.object.name)
) &&
['get', 'post', 'put', 'delete'].includes(node.callee.property.name)
) {
const routePath = node.arguments[0].value
const suggestion = getSuggestion(routePath)
if (suggestion) {
context.report({
node: node.arguments[0],
message: 'Route path should be in kebab-case.',
suggest: [
{
desc: `Change to kebab-case: ${suggestion}`,
fix: fixer => fixer.replaceText(node.arguments[0], suggestion),
},
],
})
}
}
},
}),
}
@@ -0,0 +1,49 @@
module.exports = {
meta: {
type: 'problem',
fixable: null,
docs: {
description:
'Require loadingLabel prop when isLoading is specified on OLButton',
},
schema: [],
},
create(context) {
return {
'JSXOpeningElement[name.name="OLButton"]'(node) {
const attributes = new Map(
node.attributes.map(attr => [attr.name?.name, attr])
)
const isLoadingAttr = attributes.get('isLoading')
const loadingLabelAttr = attributes.get('loadingLabel')
if (isLoadingAttr && !loadingLabelAttr) {
const isLoadingValue = isLoadingAttr.value
if (
!isLoadingValue ||
(isLoadingValue.type === 'JSXExpressionContainer' &&
isLoadingValue.expression.type === 'Literal' &&
isLoadingValue.expression.value === true)
) {
context.report({
node: isLoadingAttr,
message:
'Button with isLoading prop must also specify loadingLabel',
})
} else if (
isLoadingValue.type === 'JSXExpressionContainer' &&
isLoadingValue.expression.type !== 'Literal'
) {
context.report({
node: isLoadingAttr,
message:
'Button with isLoading prop must also specify loadingLabel',
})
}
}
},
}
},
}
@@ -0,0 +1,28 @@
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'Require Script Runner for scripts',
},
},
create(context) {
let hasImport = false
return {
ImportDeclaration(node) {
if (node.source.value.endsWith('lib/ScriptRunner.mjs')) {
hasImport = true
}
},
'Program:exit'() {
if (!hasImport) {
context.report({
loc: { line: 1, column: 0 },
message:
'Please use Script Runner for scripts. Refer to the developer manual (https://manual.dev-overleaf.com/development/code/web_scripts/#monitor-script-execution-and-usage-with-script-runner) for more information.',
})
}
},
}
},
}
@@ -0,0 +1,138 @@
const path = require('node:path')
const fs = require('node:fs')
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Ensure vi.doMock first argument is a resolvable path.',
category: 'Best Practices',
recommended: false,
url: '',
},
fixable: 'code',
hasSuggestions: true,
schema: [],
messages: {
unresolvablePath:
'The path "{{pathValue}}" in vi.doMock() cannot be resolved relative to the current file.',
notAStringLiteral:
'The first argument of vi.doMock() must be (or resolve to) a string literal representing a path.',
noArguments: 'vi.doMock() called with no arguments.',
},
},
create(context) {
const currentFilePath = context.getFilename()
// ESLint can sometimes pass <text> or <input> for snippets not in a file
if (currentFilePath === '<text>' || currentFilePath === '<input>') {
return {}
}
const currentDirectory = path.dirname(currentFilePath)
function canResolve(modulePath) {
try {
require.resolve(path.resolve(currentDirectory, modulePath))
return true
} catch (e) {
const absolutePath = path.resolve(currentDirectory, modulePath)
const extensions = [
'',
'.js',
'.mjs',
'.ts',
'.jsx',
'.tsx',
'.json',
'.node',
'/index.js',
'/index.ts',
] // Add common extensions
for (const ext of extensions) {
if (fs.existsSync(absolutePath + ext)) {
return true
}
}
return false
}
}
return {
CallExpression(node) {
if (
node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'vi' &&
node.callee.property.type === 'Identifier' &&
node.callee.property.name === 'doMock'
) {
if (node.arguments.length === 0) {
context.report({
node,
messageId: 'noArguments',
})
return
}
const firstArg = node.arguments[0]
let pathValue = firstArg.value
if (
firstArg.type !== 'Literal' ||
typeof firstArg.value !== 'string'
) {
if (firstArg.type === 'Identifier') {
const variable = context
.getScope()
.variables.find(v => v.name === firstArg.name)
if (
variable &&
variable.defs.length > 0 &&
variable.defs[0].node.init &&
variable.defs[0].node.init.type === 'Literal' &&
typeof variable.defs[0].node.init.value === 'string'
) {
pathValue = variable.defs[0].node.init.value
if (canResolve(pathValue)) {
return
}
// If the first argument was a variable that didn't resolve then we can't auto-fix it
}
}
context.report({
node: firstArg,
messageId: 'notAStringLiteral',
})
return
}
if (!pathValue.startsWith('.')) {
return
}
if (!canResolve(pathValue)) {
const mjsPath = pathValue.replace('.js', '.mjs')
const additionalReportOptions = {}
if (canResolve(mjsPath)) {
additionalReportOptions.fix = fixer =>
fixer.replaceText(firstArg, `'${mjsPath}'`)
additionalReportOptions.suggest = [
{
desc: `Replace with "${pathValue.replace('.js', '.mjs')}"`,
fix: fixer => fixer.replaceText(firstArg, `'${mjsPath}'`),
},
]
}
context.report({
node: firstArg,
messageId: 'unresolvablePath',
data: {
pathValue,
},
...additionalReportOptions,
})
}
}
},
}
},
}
+168
View File
@@ -0,0 +1,168 @@
const { RuleTester } = require('eslint')
const preferKebabUrl = require('./prefer-kebab-url')
const noUnnecessaryTrans = require('./no-unnecessary-trans')
const shouldUnescapeTrans = require('./should-unescape-trans')
const noGeneratedEditorThemes = require('./no-generated-editor-themes')
const viDoMockValidPath = require('./require-vi-doMock-valid-path')
const ruleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
},
})
ruleTester.run('prefer-kebab-url', preferKebabUrl, {
valid: [
{ code: `app.get('/foo-bar')` },
{ code: `app.get('/foo-bar/:id')` },
{ code: `router.post('/foo-bar')` },
{ code: `router.get('/foo-bar/:id/:name/:age')` },
{ code: `webRouter.get('/foo-bar/:user_id/(ProjectName)/get-info')` },
{ code: `webApp.post('/foo-bar/:user_id/(ProjectName)/get-info')` },
{
code: `router.get(/^\\/download\\/project\\/([^/]*)\\/output\\/output\\.pdf$/)`,
},
{
code: `webRouter.get(/^\\/project\\/([^/]*)\\/user\\/([0-9a-f]+)\\/build\\/([0-9a-f-]+)\\/output\\/(.*)$/)`,
},
],
invalid: [
{
code: `app.get('/fooBar')`,
errors: [{ message: 'Route path should be in kebab-case.' }],
},
{
code: `app.get('/fooBar/:id')`,
errors: [{ message: 'Route path should be in kebab-case.' }],
},
{
code: `webRouter.get('/foo_bar/:id/FooBar/:name/fooBar')`,
errors: [{ message: 'Route path should be in kebab-case.' }],
},
{
code: `router.get(/^\\/downLoad\\/pro-ject\\/([^/]*)\\/OutPut\\/out-put\\.pdf$/)`,
errors: [{ message: 'Route path should be in kebab-case.' }],
},
],
})
ruleTester.run('no-unnecessary-trans', noUnnecessaryTrans, {
valid: [
{ code: `<Trans i18nKey="test" components={{ strong: <strong/> }}/>` },
],
invalid: [
{
code: `<Trans i18nKey="test" values={{ test: 'foo '}}/>`,
errors: [{ message: `Use t('…') when there are no components` }],
},
{
code: `<Trans i18nKey="test" />`,
errors: [{ message: `Use t('…') when there are no components` }],
output: `{t('test')}`,
},
],
})
ruleTester.run('should-unescape-trans', shouldUnescapeTrans, {
valid: [
{
code: `<Trans i18nKey="test" components={{ strong: <strong/> }}/>`,
},
{
code: `<Trans i18nKey="test" values={{ foo: 'bar' }} components={{ strong: <strong/> }} shouldUnescape tOptions={{ interpolation: { escapeValue: true } }}/>`,
},
],
invalid: [
{
code: `<Trans i18nKey="test" values={{ foo: 'bar' }} components={{ strong: <strong/> }} />`,
errors: [{ message: 'Trans with values must have shouldUnescape' }],
output: `<Trans i18nKey="test" values={{ foo: 'bar' }}\nshouldUnescape components={{ strong: <strong/> }} />`,
},
{
code: `<Trans i18nKey="test" values={{ foo: 'bar' }} components={{ strong: <strong/> }} shouldUnescape />`,
errors: [
{
message:
'Trans with shouldUnescape must have tOptions.interpolation.escapeValue',
},
],
output: `<Trans i18nKey="test" values={{ foo: 'bar' }} components={{ strong: <strong/> }} shouldUnescape\ntOptions={{ interpolation: { escapeValue: true } }} />`,
},
],
})
const noGeneratedEditorThemesError =
'EditorView.theme and EditorView.baseTheme each add CSS to the page for every instance of the theme. Store the theme in a variable and reuse it instead.'
ruleTester.run('no-generated-editor-themes', noGeneratedEditorThemes, {
valid: [
{
code: `EditorView.theme({ '.cm-editor': { color: 'black' } })`,
},
{
code: `const theme = EditorView.theme({ '.cm-editor': { color: 'black' } })`,
},
],
invalid: [
{
code: `function createTheme() { return EditorView.theme({ '.cm-editor': { color: 'black' } }) }`,
errors: [
{
message: noGeneratedEditorThemesError,
},
],
},
{
code: `() => EditorView.theme({ '.cm-editor': { color: 'black' } })`,
errors: [
{
message: noGeneratedEditorThemesError,
},
],
},
{
code: `class Foo { createTheme() { return EditorView.theme({ '.cm-editor': { color: 'black' } }) } }`,
errors: [
{
message: noGeneratedEditorThemesError,
},
],
},
],
})
ruleTester.run('domock-require-valid-path', viDoMockValidPath, {
valid: [
{
code: 'vi.doMock("./require-vi-doMock-valid-path.js")',
filename: __filename,
},
{
code: 'const filename = "./require-vi-doMock-valid-path.js"; vi.doMock(filename);',
filename: __filename,
},
],
invalid: [
{
code: "vi.doMock('./require-vi-doMock-valid-path2')",
filename: __filename,
errors: [
{
message:
'The path "./require-vi-doMock-valid-path2" in vi.doMock() cannot be resolved relative to the current file.',
},
],
},
{
code: 'const filename = "./require-vi-doMock-valid-path2.js"; vi.doMock(filename);',
filename: __filename,
errors: [
{
message:
'The first argument of vi.doMock() must be (or resolve to) a string literal representing a path.',
},
],
},
],
})
@@ -0,0 +1,60 @@
module.exports = {
meta: {
type: 'problem',
fixable: 'code',
docs: {
description: 'Ensure that Trans with values has shouldUnescape',
},
},
create(context) {
return {
'JSXOpeningElement[name.name="Trans"]'(node) {
const attributes = new Map(
node.attributes.map(attr => [attr.name.name, attr])
)
if (attributes.has('values') && !attributes.has('shouldUnescape')) {
context.report({
node,
message: 'Trans with values must have shouldUnescape',
fix(fixer) {
return fixer.insertTextAfter(
attributes.get('values'),
'\nshouldUnescape' // Note: Prettier can fix indentation
)
},
})
}
if (attributes.has('values') && attributes.has('shouldUnescape')) {
const tOptions = attributes.get('tOptions')
if (!tOptions) {
context.report({
node,
message:
'Trans with shouldUnescape must have tOptions.interpolation.escapeValue',
fix(fixer) {
return fixer.insertTextAfter(
attributes.get('shouldUnescape'),
'\ntOptions={{ interpolation: { escapeValue: true } }}' // Note: Prettier can fix indentation
)
},
})
} else {
const property = tOptions.value.expression.properties
.find(p => p.key.name === 'interpolation')
?.value.properties.find(p => p.key.name === 'escapeValue')
if (property?.value.value !== true) {
context.report({
node,
message:
'Trans with shouldUnescape must have tOptions.interpolation.escapeValue set to true',
})
}
}
}
},
}
},
}
+6
View File
@@ -0,0 +1,6 @@
{
"extends": "../../tsconfig.backend.json",
"include": [
"**/*.js",
]
}
@@ -1,8 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/fetch-utils/**
libraries/o-error/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/fetch-utils/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/fetch-utils monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/fetch-utils/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'fetch-utils-eslint', name: 'fetch-utils eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/fetch-utils/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/fetch-utils monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/fetch-utils monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/fetch-utils monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'fetch-utils test results', testResults: 'libraries/fetch-utils/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/fetch-utils/reports'
sh 'make clean_jenkins -j10'
}
}
}
+1
View File
@@ -5,4 +5,5 @@ fetch-utils
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🚉 Platform
--public-repo=False
+2 -2
View File
@@ -17,10 +17,10 @@
"license": "AGPL-3.0-only",
"devDependencies": {
"@types/node-fetch": "^2.6.13",
"body-parser": "^1.20.3",
"body-parser": "1.20.4",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"express": "^4.21.2",
"express": "4.22.1",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
@@ -4,5 +4,6 @@ module.exports = {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
output: true,
},
}
-9
View File
@@ -1,9 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/fetch-utils/**
libraries/logger/**
libraries/o-error/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/logger/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/logger monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/logger/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'logger-eslint', name: 'logger eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/logger/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/logger monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/logger monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/logger monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'logger test results', testResults: 'libraries/logger/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/logger/reports'
sh 'make clean_jenkins -j10'
}
}
}
+1
View File
@@ -5,4 +5,5 @@ logger
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🚉 Platform
--public-repo=False
+20
View File
@@ -0,0 +1,20 @@
const logger = require('./')
const bunyan = require('bunyan')
const serializers = require('./serializers')
function testLogRecorder() {
const currentTest = this.currentTest
for (const level of ['error', 'fatal']) {
logger[level] = (info, msg) => {
const entry = { level, ...info, msg }
for (const [name, fn] of Object.entries(serializers)) {
if (name in entry) entry[name] = fn(entry[name])
}
currentTest.consoleErrors = (currentTest.consoleErrors || []).concat(
JSON.stringify(info, bunyan.safeCycles())
)
}
}
}
module.exports = testLogRecorder
@@ -4,5 +4,6 @@ module.exports = {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
output: true,
},
}
-7
View File
@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/metrics/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/metrics/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/metrics monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/metrics/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'metrics-eslint', name: 'metrics eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/metrics/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/metrics monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/metrics monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/metrics monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'metrics test results', testResults: 'libraries/metrics/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/metrics/reports'
sh 'make clean_jenkins -j10'
}
}
}
+1
View File
@@ -5,4 +5,5 @@ metrics
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🚉 Platform
--public-repo=False
+6
View File
@@ -97,6 +97,12 @@ function histogram(key, value, buckets, labels = {}) {
}
class Timer {
/**
* @param {string} key
* @param {number} sampleRate
* @param {Record<string, any>} labels
* @param {Array<number>} buckets
*/
constructor(key, sampleRate = 1, labels = {}, buckets = undefined) {
if (typeof sampleRate === 'object') {
// called with (key, labels, buckets)
@@ -4,5 +4,6 @@ module.exports = {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
output: true,
},
}
@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/mongo-utils/**
package-lock.json
package.json
patches/**
-72
View File
@@ -1,72 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/mongo-utils/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/mongo-utils monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/mongo-utils/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'mongo-utils-eslint', name: 'mongo-utils eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/mongo-utils/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/mongo-utils monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/mongo-utils monorepo npm run types:check'
}
}
}
}
}
post {
cleanup {
sh 'rm -rf libraries/mongo-utils/reports'
sh 'make clean_jenkins -j10'
}
}
}
+1
View File
@@ -5,4 +5,5 @@ mongo-utils
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🚉 Platform
--public-repo=False
-7
View File
@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/o-error/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/o-error/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/o-error monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/o-error/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'o-error-eslint', name: 'o-error eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/o-error/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/o-error monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/o-error monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/o-error monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'o-error test results', testResults: 'libraries/o-error/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/o-error/reports'
sh 'make clean_jenkins -j10'
}
}
}
+1
View File
@@ -5,4 +5,5 @@ o-error
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🚉 Platform
--public-repo=False
@@ -4,5 +4,6 @@ module.exports = {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
output: true,
},
}
@@ -1,12 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/fetch-utils/**
libraries/logger/**
libraries/metrics/**
libraries/o-error/**
libraries/object-persistor/**
libraries/stream-utils/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/object-persistor/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/object-persistor monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/object-persistor/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'object-persistor-eslint', name: 'object-persistor eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/object-persistor/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/object-persistor monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/object-persistor monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/object-persistor monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'object-persistor test results', testResults: 'libraries/object-persistor/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/object-persistor/reports'
sh 'make clean_jenkins -j10'
}
}
}
@@ -5,4 +5,5 @@ object-persistor
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🚉 Platform
--public-repo=False
+1 -1
View File
@@ -30,7 +30,7 @@
"@overleaf/o-error": "*",
"@overleaf/stream-utils": "*",
"fast-crc32c": "overleaf/node-fast-crc32c#aae6b2a4c7a7a159395df9cc6c38dfde702d6f51",
"glob": "^7.1.6",
"glob": "^12.0.0",
"range-parser": "^1.2.1",
"tiny-async-pool": "^1.1.0"
},
@@ -160,4 +160,38 @@ module.exports = class AbstractPersistor {
name,
})
}
/**
* List objects in a directory, returning the full keys.
*
* Suitable only for directories where the number of keys is known to be small.
*
* @param {string} location
* @param {string} prefix
* @returns {Promise<Array<string>>}
*/
async listDirectoryKeys(location, prefix) {
throw new NotImplementedError('method not implemented in persistor', {
method: 'listDirectoryKeys',
location,
prefix,
})
}
/**
* List objects in a directory, returning key and size information.
*
* Suitable only for directories where the number of keys is known to be small.
*
* @param {string} location
* @param {string} prefix
* @returns {Promise<Array<{key: string, size: number}>>}
*/
async listDirectoryStats(location, prefix) {
throw new NotImplementedError('method not implemented in persistor', {
method: 'listDirectoryStats',
location,
prefix,
})
}
}
+45 -6
View File
@@ -1,18 +1,15 @@
const crypto = require('node:crypto')
const fs = require('node:fs')
const fsPromises = require('node:fs/promises')
const globCallbacks = require('glob')
const { glob } = require('glob')
const Path = require('node:path')
const { PassThrough } = require('node:stream')
const { pipeline } = require('node:stream/promises')
const { promisify } = require('node:util')
const AbstractPersistor = require('./AbstractPersistor')
const { ReadError, WriteError, NotImplementedError } = require('./Errors')
const PersistorHelper = require('./PersistorHelper')
const glob = promisify(globCallbacks)
module.exports = class FSPersistor extends AbstractPersistor {
constructor(settings = {}) {
if (settings.storageClass) {
@@ -197,6 +194,50 @@ module.exports = class FSPersistor extends AbstractPersistor {
}
}
async listDirectoryKeys(location, name) {
const fsPath = this._getFsPath(location, name)
const paths = await this._listDirectory(fsPath)
// Filter to only return files, not directories
const files = []
for (const path of paths) {
try {
const stat = await fsPromises.stat(path)
if (stat.isFile()) {
files.push(path)
}
} catch (err) {
// ignore files that may have just been deleted
if (err.code !== 'ENOENT') {
throw err
}
}
}
return files
}
async listDirectoryStats(location, name) {
const fsPath = this._getFsPath(location, name)
const paths = await this._listDirectory(fsPath)
// Filter to only return files, not directories, with their sizes
const stats = []
for (const path of paths) {
try {
const stat = await fsPromises.stat(path)
if (stat.isFile()) {
stats.push({ key: path, size: stat.size })
}
} catch (err) {
// ignore files that may have just been deleted
if (err.code !== 'ENOENT') {
throw err
}
}
}
return stats
}
async checkIfObjectExists(location, name) {
const fsPath = this._getFsPath(location, name)
try {
@@ -305,10 +346,8 @@ 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}_*`)
}
}
+27 -6
View File
@@ -288,23 +288,25 @@ module.exports = class GcsPersistor extends AbstractPersistor {
} while (query)
}
async directorySize(bucketName, key) {
let files
const prefix = ensurePrefixIsDirectory(key)
async #listDirectory(bucketName, prefix) {
try {
const [response] = await this.storage
.bucket(bucketName)
.getFiles({ prefix })
files = response
return response
} catch (err) {
throw PersistorHelper.wrapError(
err,
'failed to list objects in GCS',
{ bucketName, key },
{ bucketName, prefix },
ReadError
)
}
}
async directorySize(bucketName, key) {
const prefix = ensurePrefixIsDirectory(key)
const files = await this.#listDirectory(bucketName, prefix)
return files.reduce(
(acc, file) => parseInt(file.metadata.size, 10) + acc,
@@ -312,6 +314,25 @@ module.exports = class GcsPersistor extends AbstractPersistor {
)
}
async listDirectoryKeys(bucketName, prefix) {
const files = await this.#listDirectory(
bucketName,
ensurePrefixIsDirectory(prefix)
)
return files.map(file => file.name)
}
async listDirectoryStats(bucketName, prefix) {
const files = await this.#listDirectory(
bucketName,
ensurePrefixIsDirectory(prefix)
)
return files.map(file => ({
key: file.name,
size: parseInt(file.metadata.size, 10),
}))
}
async checkIfObjectExists(bucketName, key) {
try {
const [response] = await this.storage
@@ -417,10 +417,20 @@ class CachedPerProjectEncryptedS3Persistor {
*
* @param {string} bucketName
* @param {string} path
* @return {Promise<ListDirectoryResult>}
* @return {Promise<string[]>}
*/
async listDirectory(bucketName, path) {
return await this.#parent.listDirectory(bucketName, path)
async listDirectoryKeys(bucketName, path) {
return await this.#parent.listDirectoryKeys(bucketName, path)
}
/**
*
* @param {string} bucketName
* @param {string} path
* @return {Promise<Array<{key: string, size: number}>>}
*/
async listDirectoryStats(bucketName, path) {
return await this.#parent.listDirectoryStats(bucketName, path)
}
/**
@@ -1,4 +1,3 @@
// Keep in sync with services/filestore/app/js/project_key.js
const path = require('node:path')
//
@@ -21,3 +20,4 @@ function naiveReverse(string) {
exports.format = format
exports.pad = pad
exports.naiveReverse = naiveReverse
+55 -2
View File
@@ -266,7 +266,7 @@ class S3Persistor extends AbstractPersistor {
* @return {Promise<void>}
*/
async deleteDirectory(bucketName, key, continuationToken) {
const { contents, response } = await this.listDirectory(
const { contents, response } = await this.#listDirectory(
bucketName,
key,
continuationToken
@@ -309,7 +309,7 @@ class S3Persistor extends AbstractPersistor {
* @param {string} [continuationToken]
* @return {Promise<ListDirectoryResult>}
*/
async listDirectory(bucketName, key, continuationToken) {
async #listDirectory(bucketName, key, continuationToken) {
let response
const options = { Bucket: bucketName, Prefix: key }
if (continuationToken) {
@@ -535,6 +535,59 @@ class S3Persistor extends AbstractPersistor {
}
}
/**
* @param {string} bucketName
* @param {string} prefix
* @return {Promise<Array<string>>}
*/
async listDirectoryKeys(bucketName, prefix) {
const keys = []
let continuationToken
do {
const { contents, response } = await this.#listDirectory(
bucketName,
prefix,
continuationToken
)
keys.push(...contents.map(item => item.Key || ''))
continuationToken = response.IsTruncated
? response.NextContinuationToken
: undefined
} while (continuationToken)
return keys
}
/**
* @param {string} bucketName
* @param {string} prefix
* @return {Promise<Array<{key: string, size: number}>>}
*/
async listDirectoryStats(bucketName, prefix) {
const stats = []
let continuationToken
do {
const { contents, response } = await this.#listDirectory(
bucketName,
prefix,
continuationToken
)
stats.push(
...contents.map(item => ({
key: item.Key || '',
size: item.Size ?? -1,
}))
)
continuationToken = response.IsTruncated
? response.NextContinuationToken
: undefined
} while (continuationToken)
return stats
}
/**
* @param {string} bucket
* @return {S3Client}
@@ -4,5 +4,6 @@ module.exports = {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
output: true,
},
}
+1 -1
View File
@@ -27,7 +27,7 @@ SandboxedModule.configure({
globals: { Buffer, Math, console, process, URL },
sourceTransformers: {
removeNodePrefix: function (source) {
return source.replace(/require\(['"]node:/g, "require('")
return source.replace(/require\((['"])node:/g, 'require($1')
},
},
})
@@ -400,6 +400,56 @@ describe('FSPersistorTests', function () {
).to.equal(0)
})
})
describe('listDirectoryKeys', function () {
beforeEach(async function () {
for (const file of Object.values(files)) {
await persistor.sendFile(location, file, '/uploads/info.txt')
}
})
it('should list directory keys', async function () {
const keys = await persistor.listDirectoryKeys(location, 'animals')
expect(keys).to.have.lengthOf(2)
expect(keys).to.include(scenario.fsPath(files.wombat))
expect(keys).to.include(scenario.fsPath(files.giraffe))
})
it('should return empty array for non-existing directories', async function () {
const keys = await persistor.listDirectoryKeys(
location,
'does-not-exist'
)
expect(keys).to.deep.equal([])
})
})
describe('listDirectoryStats', function () {
beforeEach(async function () {
for (const file of Object.values(files)) {
await persistor.sendFile(location, file, '/uploads/info.txt')
}
})
it('should list directory stats', async function () {
const stats = await persistor.listDirectoryStats(location, 'animals')
expect(stats).to.have.lengthOf(2)
const keys = stats.map(s => s.key)
expect(keys).to.include(scenario.fsPath(files.wombat))
expect(keys).to.include(scenario.fsPath(files.giraffe))
for (const stat of stats) {
expect(stat.size).to.equal(localFiles['/uploads/info.txt'].length)
}
})
it('should return empty array for non-existing directories', async function () {
const stats = await persistor.listDirectoryStats(
location,
'does-not-exist'
)
expect(stats).to.deep.equal([])
})
})
})
}
})
@@ -723,4 +723,127 @@ describe('GcsPersistorTests', function () {
})
})
})
describe('listDirectoryKeys', function () {
describe('with valid parameters', function () {
let keys
beforeEach(async function () {
const filesWithNames = files.map((file, i) => ({
...file,
name: i === 0 ? 'llama' : 'hippo',
}))
GcsBucket.getFiles.resolves([filesWithNames])
keys = await GcsPersistor.listDirectoryKeys(bucket, key)
})
it('should list the objects in the directory', function () {
expect(Storage.prototype.bucket).to.have.been.calledWith(bucket)
expect(GcsBucket.getFiles).to.have.been.calledWith({
prefix: `${key}/`,
})
})
it('should return the keys', function () {
expect(keys).to.deep.equal(['llama', 'hippo'])
})
})
describe('when there are no files', function () {
let keys
beforeEach(async function () {
GcsBucket.getFiles.resolves([[]])
keys = await GcsPersistor.listDirectoryKeys(bucket, key)
})
it('should return an empty array', function () {
expect(keys).to.deep.equal([])
})
})
describe('when there is an error listing the objects', function () {
let error
beforeEach(async function () {
GcsBucket.getFiles.rejects(genericError)
try {
await GcsPersistor.listDirectoryKeys(bucket, key)
} catch (err) {
error = err
}
})
it('should generate a ReadError', function () {
expect(error).to.be.an.instanceOf(Errors.ReadError)
})
it('should wrap the error', function () {
expect(error.cause).to.equal(genericError)
})
})
})
describe('listDirectoryStats', function () {
describe('with valid parameters', function () {
let stats
beforeEach(async function () {
const filesWithNames = files.map((file, i) => ({
...file,
name: i === 0 ? 'llama' : 'hippo',
}))
GcsBucket.getFiles.resolves([filesWithNames])
stats = await GcsPersistor.listDirectoryStats(bucket, key)
})
it('should list the objects in the directory', function () {
expect(Storage.prototype.bucket).to.have.been.calledWith(bucket)
expect(GcsBucket.getFiles).to.have.been.calledWith({
prefix: `${key}/`,
})
})
it('should return the stats', function () {
expect(stats).to.deep.equal([
{ key: 'llama', size: 11 },
{ key: 'hippo', size: 22 },
])
})
})
describe('when there are no files', function () {
let stats
beforeEach(async function () {
GcsBucket.getFiles.resolves([[]])
stats = await GcsPersistor.listDirectoryStats(bucket, key)
})
it('should return an empty array', function () {
expect(stats).to.deep.equal([])
})
})
describe('when there is an error listing the objects', function () {
let error
beforeEach(async function () {
GcsBucket.getFiles.rejects(genericError)
try {
await GcsPersistor.listDirectoryStats(bucket, key)
} catch (err) {
error = err
}
})
it('should generate a ReadError', function () {
expect(error).to.be.an.instanceOf(Errors.ReadError)
})
it('should wrap the error', function () {
expect(error.cause).to.equal(genericError)
})
})
})
})
@@ -1,8 +1,6 @@
'use strict'
const { expect } = require('chai')
const { format, pad } = require('../../../../storage/lib/project_key')
const { format, pad } = require('../../src/ProjectKey.js')
describe('projectKey', function () {
it('reverses padded keys', function () {
@@ -1046,4 +1046,215 @@ describe('S3PersistorTests', function () {
})
})
})
describe('listDirectoryKeys', function () {
describe('with valid parameters', function () {
let keys
beforeEach(async function () {
S3.mockSend(S3.ListObjectsV2Command, {
Contents: files.map(file => ({ Key: file.Key })),
IsTruncated: false,
})
keys = await S3Persistor.listDirectoryKeys(bucket, key)
})
it('should list the objects in the directory', function () {
S3.assertSendCalledWith(S3.ListObjectsV2Command, {
Bucket: bucket,
Prefix: key,
})
})
it('should return the keys', function () {
expect(keys).to.deep.equal(['llama', 'hippo'])
})
})
describe('when there are no files', function () {
let keys
beforeEach(async function () {
S3.mockSend(S3.ListObjectsV2Command, {
Contents: [],
IsTruncated: false,
})
keys = await S3Persistor.listDirectoryKeys(bucket, key)
})
it('should return an empty array', function () {
expect(keys).to.deep.equal([])
})
})
describe('when there are more files available', function () {
const continuationToken = 'wombat'
let keys
beforeEach(async function () {
S3.mockSend(
S3.ListObjectsV2Command,
{
Contents: [files[0]].map(file => ({ Key: file.Key })),
IsTruncated: true,
NextContinuationToken: continuationToken,
},
{
nextResponses: [
{
Contents: [files[1]].map(file => ({ Key: file.Key })),
IsTruncated: false,
},
],
}
)
keys = await S3Persistor.listDirectoryKeys(bucket, key)
})
it('should list the objects in multiple calls', function () {
S3.assertSendCallCount(S3.ListObjectsV2Command, 2)
expect(S3.s3ClientStub.send.firstCall.args[0].payload).to.deep.equal({
Bucket: bucket,
Prefix: key,
})
expect(S3.s3ClientStub.send.secondCall.args[0].payload).to.deep.equal({
Bucket: bucket,
Prefix: key,
ContinuationToken: continuationToken,
})
})
it('should return all keys', function () {
expect(keys).to.deep.equal(['llama', 'hippo'])
})
})
describe('when there is an error listing the objects', function () {
let error
beforeEach(async function () {
S3.mockSend(S3.ListObjectsV2Command, genericError, { rejects: true })
try {
await S3Persistor.listDirectoryKeys(bucket, key)
} catch (err) {
error = err
}
})
it('should generate a ReadError', function () {
expect(error).to.be.an.instanceOf(Errors.ReadError)
})
it('should wrap the error', function () {
expect(error.cause).to.exist
})
})
})
describe('listDirectoryStats', function () {
describe('with valid parameters', function () {
let stats
beforeEach(async function () {
S3.mockSend(S3.ListObjectsV2Command, {
Contents: files.map(file => ({ Key: file.Key, Size: file.Size })),
IsTruncated: false,
})
stats = await S3Persistor.listDirectoryStats(bucket, key)
})
it('should list the objects in the directory', function () {
S3.assertSendCalledWith(S3.ListObjectsV2Command, {
Bucket: bucket,
Prefix: key,
})
})
it('should return the stats', function () {
expect(stats).to.deep.equal([
{ key: 'llama', size: 11 },
{ key: 'hippo', size: 22 },
])
})
})
describe('when there are no files', function () {
let stats
beforeEach(async function () {
S3.mockSend(S3.ListObjectsV2Command, {
Contents: [],
IsTruncated: false,
})
stats = await S3Persistor.listDirectoryStats(bucket, key)
})
it('should return an empty array', function () {
expect(stats).to.deep.equal([])
})
})
describe('when there are more files available', function () {
const continuationToken = 'wombat'
let stats
beforeEach(async function () {
S3.mockSend(
S3.ListObjectsV2Command,
{
Contents: [files[0]].map(file => ({
Key: file.Key,
Size: file.Size,
})),
IsTruncated: true,
NextContinuationToken: continuationToken,
},
{
nextResponses: [
{
Contents: [files[1]].map(file => ({
Key: file.Key,
Size: file.Size,
})),
IsTruncated: false,
},
],
}
)
stats = await S3Persistor.listDirectoryStats(bucket, key)
})
it('should list the objects in multiple calls', function () {
S3.assertSendCallCount(S3.ListObjectsV2Command, 2)
})
it('should return all stats', function () {
expect(stats).to.deep.equal([
{ key: 'llama', size: 11 },
{ key: 'hippo', size: 22 },
])
})
})
describe('when there is an error listing the objects', function () {
let error
beforeEach(async function () {
S3.mockSend(S3.ListObjectsV2Command, genericError, { rejects: true })
try {
await S3Persistor.listDirectoryStats(bucket, key)
} catch (err) {
error = err
}
})
it('should generate a ReadError', function () {
expect(error).to.be.an.instanceOf(Errors.ReadError)
})
it('should wrap the error', function () {
expect(error.cause).to.exist
})
})
})
})
@@ -1,8 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/o-error/**
libraries/overleaf-editor-core/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/overleaf-editor-core/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/overleaf-editor-core monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/overleaf-editor-core/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'overleaf-editor-core-eslint', name: 'overleaf-editor-core eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/overleaf-editor-core/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/overleaf-editor-core monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/overleaf-editor-core monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/overleaf-editor-core monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'overleaf-editor-core test results', testResults: 'libraries/overleaf-editor-core/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/overleaf-editor-core/reports'
sh 'make clean_jenkins -j10'
}
}
}
@@ -5,4 +5,5 @@ overleaf-editor-core
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🥑 Core
--public-repo=False
@@ -4,5 +4,6 @@ module.exports = {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
output: true,
},
}
@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/promise-utils/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/promise-utils/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/promise-utils monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/promise-utils/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'promise-utils-eslint', name: 'promise-utils eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/promise-utils/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/promise-utils monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/promise-utils monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/promise-utils monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'promise-utils test results', testResults: 'libraries/promise-utils/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/promise-utils/reports'
sh 'make clean_jenkins -j10'
}
}
}
+1
View File
@@ -5,4 +5,5 @@ promise-utils
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🚉 Platform
--public-repo=False
@@ -4,5 +4,6 @@ module.exports = {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
output: true,
},
}
@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/ranges-tracker/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/ranges-tracker/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/ranges-tracker monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/ranges-tracker/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'ranges-tracker-eslint', name: 'ranges-tracker eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/ranges-tracker/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/ranges-tracker monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/ranges-tracker monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/ranges-tracker monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'ranges-tracker test results', testResults: 'libraries/ranges-tracker/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/ranges-tracker/reports'
sh 'make clean_jenkins -j10'
}
}
}
+1
View File
@@ -5,4 +5,5 @@ ranges-tracker
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🥑 Core
--public-repo=False
@@ -4,5 +4,6 @@ module.exports = {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
output: true,
},
}
@@ -1,10 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/fetch-utils/**
libraries/logger/**
libraries/o-error/**
libraries/redis-wrapper/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/redis-wrapper/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/redis-wrapper monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/redis-wrapper/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'redis-wrapper-eslint', name: 'redis-wrapper eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/redis-wrapper/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/redis-wrapper monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/redis-wrapper monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/redis-wrapper monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'redis-wrapper test results', testResults: 'libraries/redis-wrapper/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/redis-wrapper/reports'
sh 'make clean_jenkins -j10'
}
}
}
+1
View File
@@ -5,4 +5,5 @@ redis-wrapper
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🚉 Platform
--public-repo=False
@@ -4,5 +4,6 @@ module.exports = {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
output: true,
},
}
-7
View File
@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/settings/**
package-lock.json
package.json
patches/**
-72
View File
@@ -1,72 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/settings/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/settings monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/settings/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'settings-eslint', name: 'settings eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/settings/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/settings monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/settings monorepo npm run types:check'
}
}
}
}
}
post {
cleanup {
sh 'rm -rf libraries/settings/reports'
sh 'make clean_jenkins -j10'
}
}
}
+1
View File
@@ -5,4 +5,5 @@ settings
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🚉 Platform
--public-repo=False
@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/stream-utils/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/stream-utils/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/stream-utils monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/stream-utils/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'stream-utils-eslint', name: 'stream-utils eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/stream-utils/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/stream-utils monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/stream-utils monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/stream-utils monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'stream-utils test results', testResults: 'libraries/stream-utils/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/stream-utils/reports'
sh 'make clean_jenkins -j10'
}
}
}
+1
View File
@@ -5,4 +5,5 @@ stream-utils
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--pipeline-owner=🚉 Platform
--public-repo=False
@@ -4,5 +4,6 @@ module.exports = {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
output: true,
},
}
@@ -1,8 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/o-error/**
libraries/validation-tools/**
package-lock.json
package.json
patches/**
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/validation-tools/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/validation-tools monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/validation-tools/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'validation-tools-eslint', name: 'validation-tools eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/validation-tools/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/validation-tools monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/validation-tools monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/validation-tools monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'validation-tools test results', testResults: 'libraries/validation-tools/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/validation-tools/reports'
sh 'make clean_jenkins -j10'
}
}
}
@@ -0,0 +1,17 @@
const { isZodErrorLike, fromError } = require('zod-validation-error')
function createHandleValidationError(statusCode = 400) {
return [
(err, req, res, next) => {
if (!isZodErrorLike(err)) {
return next(err)
}
res.status(statusCode).json({ ...fromError(err), statusCode })
},
]
}
const handleValidationError = createHandleValidationError(400)
module.exports = { handleValidationError, createHandleValidationError }
+10 -2
View File
@@ -1,11 +1,19 @@
const { ParamsError } = require('./Errors')
const { z } = require('zod')
const { zz } = require('./zodHelpers')
const { validateReq } = require('./validateReq')
const { parseReq } = require('./parseReq')
const { validateSchema } = require('./validateSchema')
const {
handleValidationError,
createHandleValidationError,
} = require('./handleValidationError')
module.exports = {
z,
zz,
validateReq,
validateSchema,
parseReq,
handleValidationError,
createHandleValidationError,
ParamsError,
}
+3 -2
View File
@@ -22,10 +22,11 @@
"dependencies": {
"@overleaf/o-error": "*",
"mongodb": "^6.12.0",
"zod": "^4.1.8"
"zod": "^4.1.8",
"zod-validation-error": "^4.0.1"
},
"devDependencies": {
"typescript": "^5.0.4",
"vitest": "^3.2.4"
"vitest": "^4.0.0"
}
}
@@ -12,14 +12,14 @@ const { ParamsError } = require('./Errors')
*/
/**
* Validate a request against a zod schema
* Parse and validate a request against a Zod schema
*
* @template {ZodType} T
* @param {Request} req - The Express request object
* @param {T} schema - The Zod schema to validate against
* @returns {output<T>} The validated request object
*/
function validateReq(req, schema) {
function parseReq(req, schema) {
const parsed = schema.safeParse(req)
if (parsed.success) {
return parsed.data
@@ -31,4 +31,4 @@ function validateReq(req, schema) {
}
}
module.exports = { validateReq }
module.exports = { parseReq }
@@ -1,10 +1,10 @@
import { validateReq } from '../../../validateReq'
import { parseReq } from '../../../parseReq'
import { describe, expect, it } from 'vitest'
import { z } from 'zod'
import type { Request } from 'express'
import { zz } from '../../../zodHelpers'
describe('validateReq', () => {
describe('parseReq', () => {
describe('with a request that is valid for the schema', () => {
it('should return the parsed request', () => {
const req = {
@@ -25,7 +25,7 @@ describe('validateReq', () => {
}),
})
const result = validateReq(req, schema)
const result = parseReq(req, schema)
expect(result).toEqual({
params: {
@@ -46,7 +46,7 @@ describe('validateReq', () => {
} as Request<{ id: string }>
expect(() =>
validateReq(
parseReq(
req,
z.object({
params: z.object({
@@ -65,7 +65,7 @@ describe('validateReq', () => {
} as Request
expect(() =>
validateReq(
parseReq(
req,
z.object({
body: z.object({
@@ -41,4 +41,180 @@ describe('zodHelpers', () => {
expect(parsed.data?.toString()).toBe('507f1f77bcf86cd799439011')
})
})
describe('datetime', () => {
it('parses valid ISO 8601 datetime strings', () => {
const parsed = zz.datetime().safeParse('2024-01-01T12:00:00Z')
expect(parsed.success).toBe(true)
expect(parsed.data).toEqual(new Date('2024-01-01T12:00:00Z'))
})
it('parses a valid ISO 8601 datetime with offset', () => {
const parsed = zz
.datetime({ offset: true })
.safeParse('2024-01-01T12:00:00+00:00')
expect(parsed.success).toBe(true)
expect(parsed.data).toEqual(new Date('2024-01-01T12:00:00+00:00'))
})
it('parses a valid Date object', () => {
const date = new Date('2024-01-01T12:00:00Z')
const parsed = zz.datetime().safeParse(date)
expect(parsed.success).toBe(true)
expect(parsed.data).toEqual(date)
})
it('fails to parse datetime with offset when offset option is false', () => {
const parsed = zz
.datetime({ offset: false })
.safeParse('2024-01-01T12:00:00+00:00')
expect(parsed.success).toBe(false)
expect(parsed.error?.issues).toHaveLength(1)
expect(parsed.error?.issues).toMatchObject([
expect.objectContaining({
code: 'invalid_format',
format: 'datetime',
message: 'Invalid ISO datetime',
}),
])
})
it('fails to parse null when schema is not nullable', () => {
const parsed = zz.datetime().safeParse(null)
expect(parsed.success).toBe(false)
expect(parsed.error?.message).toContain(
'Invalid input: expected date, received null'
)
})
it('fails to parse invalid datetime strings', () => {
const parsed = zz.datetime().safeParse('invalid-datetime')
expect(parsed.success).toBe(false)
expect(parsed.error?.issues).toHaveLength(1)
expect(parsed.error?.issues).toMatchObject([
expect.objectContaining({
code: 'invalid_format',
format: 'datetime',
message: 'Invalid ISO datetime',
}),
])
})
})
describe('datetimeNullable', () => {
it('parses valid ISO 8601 datetime strings', () => {
const parsed = zz.datetimeNullable().safeParse('2024-01-01T12:00:00Z')
expect(parsed.success).toBe(true)
expect(parsed.data).toEqual(new Date('2024-01-01T12:00:00Z'))
})
it('parses a valid ISO 8601 datetime with offset', () => {
const parsed = zz
.datetimeNullable({ offset: true })
.safeParse('2024-01-01T12:00:00+00:00')
expect(parsed.success).toBe(true)
expect(parsed.data).toEqual(new Date('2024-01-01T12:00:00+00:00'))
})
it('parses a valid Date object', () => {
const date = new Date('2024-01-01T12:00:00Z')
const parsed = zz.datetimeNullable().safeParse(date)
expect(parsed.success).toBe(true)
expect(parsed.data).toEqual(date)
})
it('fails to parse datetime with offset when offset option is false', () => {
const parsed = zz
.datetimeNullable({ offset: false })
.safeParse('2024-01-01T12:00:00+00:00')
expect(parsed.success).toBe(false)
expect(parsed.error?.issues).toHaveLength(1)
expect(parsed.error?.issues).toMatchObject([
expect.objectContaining({
code: 'invalid_format',
format: 'datetime',
message: 'Invalid ISO datetime',
}),
])
})
it('parses null when schema is nullable and input is null', () => {
const parsed = zz.datetimeNullable().safeParse(null)
expect(parsed.success).toBe(true)
expect(parsed.data).toBeNull()
})
it('fails to parse invalid datetime strings', () => {
const parsed = zz.datetimeNullable().safeParse('invalid-datetime')
expect(parsed.success).toBe(false)
expect(parsed.error?.issues).toHaveLength(1)
expect(parsed.error?.issues).toMatchObject([
expect.objectContaining({
code: 'invalid_format',
format: 'datetime',
message: 'Invalid ISO datetime',
}),
])
})
})
describe('datetimeNullish', () => {
it('parses valid ISO 8601 datetime strings', () => {
const parsed = zz.datetimeNullish().safeParse('2024-01-01T12:00:00Z')
expect(parsed.success).toBe(true)
expect(parsed.data).toEqual(new Date('2024-01-01T12:00:00Z'))
})
it('parses a valid ISO 8601 datetime with offset', () => {
const parsed = zz
.datetimeNullish({ offset: true })
.safeParse('2024-01-01T12:00:00+00:00')
expect(parsed.success).toBe(true)
expect(parsed.data).toEqual(new Date('2024-01-01T12:00:00+00:00'))
})
it('parses a valid Date object', () => {
const date = new Date('2024-01-01T12:00:00Z')
const parsed = zz.datetimeNullish().safeParse(date)
expect(parsed.success).toBe(true)
expect(parsed.data).toEqual(date)
})
it('parses null when schema is nullable and input is null', () => {
const parsed = zz.datetimeNullish().safeParse(null)
expect(parsed.success).toBe(true)
expect(parsed.data).toBeNull()
})
it('parses undefined when schema is nullish and input is undefined', () => {
const parsed = zz.datetimeNullish().safeParse(undefined)
expect(parsed.success).toBe(true)
expect(parsed.data).toBeUndefined()
})
it('fails to parse datetime with offset when offset option is false', () => {
const parsed = zz
.datetimeNullish({ offset: false })
.safeParse('2024-01-01T12:00:00+00:00')
expect(parsed.success).toBe(false)
expect(parsed.error?.issues).toHaveLength(1)
expect(parsed.error?.issues).toMatchObject([
expect.objectContaining({
code: 'invalid_format',
format: 'datetime',
message: 'Invalid ISO datetime',
}),
])
})
it('fails to parse invalid datetime strings', () => {
const parsed = zz.datetimeNullish().safeParse('invalid-datetime')
expect(parsed.success).toBe(false)
expect(parsed.error?.issues).toHaveLength(1)
expect(parsed.error?.issues).toMatchObject([
expect.objectContaining({
code: 'invalid_format',
format: 'datetime',
message: 'Invalid ISO datetime',
}),
])
})
})
})
+6
View File
@@ -0,0 +1,6 @@
import z from 'zod'
export interface DatetimeSchemaOptions extends z.core.$ZodISODateTimeParams {
allowNull?: boolean
allowUndefined?: boolean
}
@@ -0,0 +1,66 @@
// @ts-check
const { isZodErrorLike } = require('zod-validation-error')
/**
* @typedef {import('zod').ZodType} ZodType
*/
/**
* @template T
* @typedef {import('zod').output<T>} output<T>
*/
/**
* A helper function to safely get a nested value from an object
* using a path array (e.g., ["query", "resource_type"])
* @param {any} data
* @param {Array<PropertyKey>} path
*/
function getPathValue(data, path) {
let current = data
for (const key of path) {
if (current === null || typeof current !== 'object') {
return undefined
}
current = current[key]
}
return current
}
/**
* @param {any} issue
* @param {any} value
*/
const isRequiredError = (issue, value) =>
value === undefined &&
(issue.code === 'invalid_type' || issue.code === 'invalid_union')
/**
* Validates data against a Zod schema and throws a user-friendly error.
*
* @template {ZodType} T
* @param {T} schema - The Zod schema
* @param {unknown} data - The data to validate
* @returns {output<T>} The validated (and transformed) data
*/
function validateSchema(schema, data) {
try {
return schema.parse(data)
} catch (err) {
if (isZodErrorLike(err)) {
const errorMessages = err.issues.map(issue => {
const value = getPathValue(data, issue.path)
const fieldName = String(issue.path[issue.path.length - 1])
if (isRequiredError(issue, value)) {
return `"${fieldName}" is required`
}
return `"${fieldName}" - ` + issue.message
})
throw new Error(errorMessages.join('; '))
}
throw err
}
}
module.exports = { validateSchema }
+21
View File
@@ -3,6 +3,23 @@ const mongodb = require('mongodb')
const { ObjectId } = mongodb
/**
* @import { DatetimeSchemaOptions } from './types'
*/
/**
* @param {DatetimeSchemaOptions} options
*/
const datetimeSchema = ({ allowNull, allowUndefined, ...zodOptions } = {}) => {
const union = [z.date(), z.iso.datetime(zodOptions)]
if (allowNull) union.push(z.null())
if (allowUndefined) union.push(z.undefined())
return z.union(union).transform(dt => {
if (allowNull && !dt) return dt === null ? null : undefined
return dt instanceof Date ? dt : new Date(dt)
})
}
const zz = {
objectId: () =>
z.string().refine(ObjectId.isValid, { message: 'invalid Mongo ObjectId' }),
@@ -12,6 +29,10 @@ const zz = {
.refine(ObjectId.isValid, { message: 'invalid Mongo ObjectId' })
.transform(val => new ObjectId(val)),
hex: () => z.string().regex(/^[0-9a-f]*$/),
datetime: options => datetimeSchema(options),
datetimeNullable: options => datetimeSchema({ ...options, allowNull: true }),
datetimeNullish: options =>
datetimeSchema({ ...options, allowNull: true, allowUndefined: true }),
}
module.exports = { zz }
+11041 -4266
View File
File diff suppressed because it is too large Load Diff
+11 -10
View File
@@ -8,8 +8,9 @@
"@types/chai": "^4.3.0",
"@types/chai-as-promised": "^7.1.8",
"@types/mocha": "^10.0.6",
"@typescript-eslint/eslint-plugin": "^8.30.1",
"@typescript-eslint/parser": "^8.30.1",
"@typescript-eslint/eslint-plugin": "8.50.0",
"@typescript-eslint/parser": "^8.50.0",
"@vitest/eslint-plugin": "^1.5.0",
"eslint": "^8.15.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-standard": "^17.0.0",
@@ -22,22 +23,21 @@
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-unicorn": "^56.0.0",
"prettier": "3.6.2",
"prettier": "3.7.4",
"prettier-plugin-groovy": "0.2.1",
"typescript": "^5.8.3"
"typescript": "^5.9.3"
},
"engines": {
"npm": "11.4.2"
},
"overrides": {
"swagger-tools@0.10.4": {
"path-to-regexp": "3.3.0",
"body-parser": "1.20.3",
"multer": "2.0.2"
},
"request@2.88.2": {
"tough-cookie": "5.1.2",
"form-data": "2.5.5"
"form-data": "2.5.5",
"qs": "6.14.1"
},
"streamdown": {
"mermaid": "file:./services/web/stubs/mermaid-stub"
}
},
"scripts": {
@@ -76,6 +76,7 @@
"services/third-party-references",
"services/tpdsworker",
"services/web",
"tools/dependency-management",
"tools/saas-e2e",
"tools/migrations"
]
@@ -1,37 +1,35 @@
diff --git a/node_modules/@google-cloud/storage/node_modules/teeny-request/build/src/index.js b/node_modules/@google-cloud/storage/node_modules/teeny-request/build/src/index.js
index a2251ca..e29e796 100644
index af5d15e..8a9bf77 100644
--- a/node_modules/@google-cloud/storage/node_modules/teeny-request/build/src/index.js
+++ b/node_modules/@google-cloud/storage/node_modules/teeny-request/build/src/index.js
@@ -166,27 +166,27 @@ function teenyRequest(reqOpts, callback) {
}
if (callback === undefined) {
@@ -168,31 +168,34 @@ function teenyRequest(reqOpts, callback) {
// Stream mode
- const requestStream = streamEvents(new stream_1.PassThrough());
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
const requestStream = streamEvents(new stream_1.PassThrough());
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- let responseStream;
- requestStream.once('reading', () => {
- if (responseStream) {
- responseStream.pipe(requestStream);
- (0, stream_1.pipeline)(responseStream, requestStream, () => { });
- }
- else {
- requestStream.once('response', () => {
- responseStream.pipe(requestStream);
- (0, stream_1.pipeline)(responseStream, requestStream, () => { });
- });
- }
- });
+ const requestStream = new stream_1.PassThrough();
+ // // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ // let responseStream;
+ // requestStream.once('reading', () => {
+ // if (responseStream) {
+ // responseStream.pipe(requestStream);
+ // }
+ // else {
+ // requestStream.once('response', () => {
+ // responseStream.pipe(requestStream);
+ // });
+ // }
+ // if (responseStream) {
+ // (0, stream_1.pipeline)(responseStream, requestStream, () => { });
+ // }
+ // else {
+ // requestStream.once('response', () => {
+ // (0, stream_1.pipeline)(responseStream, requestStream, () => { });
+ // });
+ // }
+ // });
+
+
options.compress = false;
teenyRequest.stats.requestStarting();
(0, node_fetch_1.default)(uri, options).then(res => {
@@ -41,10 +39,17 @@ index a2251ca..e29e796 100644
- requestStream.emit('error', err);
- });
+ teenyRequest.stats.requestFinished(); stream_1.pipeline(res.body, requestStream, () => {});
+ // responseStream = res.body;
+ // responseStream.on('error', (err) => {
+ // requestStream.emit('error', err);
+ // });
+ // responseStream = res.body;
+ // responseStream.on('error', (err) => {
+ // requestStream.emit('error', err);
+ // });
const response = fetchToRequestResponse(options, res);
requestStream.emit('response', response);
}, err => {
teenyRequest.stats.requestFinished();
requestStream.emit('error', err);
});
+
// fetch doesn't supply the raw HTTP stream, instead it
// returns a PassThrough piped from the HTTP response
// stream.
-23
View File
@@ -1,23 +0,0 @@
diff --git a/node_modules/@node-saml/node-saml/lib/saml.js b/node_modules/@node-saml/node-saml/lib/saml.js
index fba15b9..a5778cb 100644
--- a/node_modules/@node-saml/node-saml/lib/saml.js
+++ b/node_modules/@node-saml/node-saml/lib/saml.js
@@ -336,7 +336,8 @@ class SAML {
const requestOrResponse = request || response;
(0, utility_1.assertRequired)(requestOrResponse, "either request or response is required");
let buffer;
- if (this.options.skipRequestCompression) {
+ // logout requestOrResponse must be compressed anyway
+ if (this.options.skipRequestCompression && operation !== "logout") {
buffer = Buffer.from(requestOrResponse, "utf8");
}
else {
@@ -495,7 +496,7 @@ class SAML {
try {
xml = Buffer.from(container.SAMLResponse, "base64").toString("utf8");
doc = await (0, xml_1.parseDomFromString)(xml);
- const inResponseToNodes = xml_1.xpath.selectAttributes(doc, "/*[local-name()='Response']/@InResponseTo");
+ const inResponseToNodes = xml_1.xpath.selectAttributes(doc, "/*[local-name()='Response' or local-name()='LogoutResponse']/@InResponseTo");
if (inResponseToNodes) {
inResponseTo = inResponseToNodes.length ? inResponseToNodes[0].nodeValue : null;
await this.validateInResponseTo(inResponseTo);
-64
View File
@@ -1,64 +0,0 @@
diff --git a/node_modules/ldapauth-fork/lib/ldapauth.js b/node_modules/ldapauth-fork/lib/ldapauth.js
index 85ecf36a8b..a7d07e0f78 100644
--- a/node_modules/ldapauth-fork/lib/ldapauth.js
+++ b/node_modules/ldapauth-fork/lib/ldapauth.js
@@ -69,6 +69,7 @@ function LdapAuth(opts) {
this.opts.bindProperty || (this.opts.bindProperty = 'dn');
this.opts.groupSearchScope || (this.opts.groupSearchScope = 'sub');
this.opts.groupDnProperty || (this.opts.groupDnProperty = 'dn');
+ this.opts.tlsStarted = false;
EventEmitter.call(this);
@@ -108,21 +109,7 @@ function LdapAuth(opts) {
this._userClient.on('error', this._handleError.bind(this));
var self = this;
- if (this.opts.starttls) {
- // When starttls is enabled, this callback supplants the 'connect' callback
- this._adminClient.starttls(this.opts.tlsOptions, this._adminClient.controls, function(err) {
- if (err) {
- self._handleError(err);
- } else {
- self._onConnectAdmin();
- }
- });
- this._userClient.starttls(this.opts.tlsOptions, this._userClient.controls, function(err) {
- if (err) {
- self._handleError(err);
- }
- });
- } else if (opts.reconnect) {
+ if (opts.reconnect && !this.opts.starttls) {
this.once('_installReconnectListener', function() {
self.log && self.log.trace('install reconnect listener');
self._adminClient.on('connect', function() {
@@ -384,6 +371,28 @@ LdapAuth.prototype._findGroups = function(user, callback) {
*/
LdapAuth.prototype.authenticate = function(username, password, callback) {
var self = this;
+ if (this.opts.starttls && !this.opts.tlsStarted) {
+ // When starttls is enabled, this callback supplants the 'connect' callback
+ this._adminClient.starttls(this.opts.tlsOptions, this._adminClient.controls, function (err) {
+ if (err) {
+ self._handleError(err);
+ } else {
+ self._onConnectAdmin(function(){self._handleAuthenticate(username, password, callback);});
+ }
+ });
+ this._userClient.starttls(this.opts.tlsOptions, this._userClient.controls, function (err) {
+ if (err) {
+ self._handleError(err);
+ }
+ });
+ } else {
+ self._handleAuthenticate(username, password, callback);
+ }
+};
+
+LdapAuth.prototype._handleAuthenticate = function (username, password, callback) {
+ this.opts.tlsStarted = true;
+ var self = this;
if (typeof password === 'undefined' || password === null || password === '') {
return callback(new Error('no password given'));

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