Commit Graph

9381 Commits

Author SHA1 Message Date
Alp Keser 056dfc1367 Merge pull request #2528 from basecamp/mobile/missing-boards-fix
Update boards JSON to return all accessible boards ordered by recently accessed
2026-02-18 13:20:49 +03:00
Alp Keser 610cf7a190 Merge pull request #2398 from basecamp/notifications-tray-api
Add JSON response support for `notifications/tray`
2026-02-18 13:19:59 +03:00
Jeremy Daer 8da0c47a5f Add actionpack-xml_parser to Gemfile.saas (production bundle)
The prior commit added it to saas/Gemfile but the production Docker
build uses Gemfile.saas (via BUNDLE_GEMFILE). This ensures the XML
parameter parser is present in the actual runtime environment.
2026-02-17 20:37:31 -08:00
Jeremy Daer 475fb63c6d Add actionpack-xml_parser for Queenbee sync request support (#2563)
Queenbee sends account sync/cancel/etc requests as XML via
ActiveResource, including the queenbee_signature in the XML body.
Rails removed built-in XML parameter parsing in Rails 4.0, so without
this gem the XML body is silently ignored and the signature check
always fails with 403.
2026-02-17 20:34:33 -08:00
Kevin McConnell b2b8465ae8 Merge pull request #2558 from basecamp/correct-card-url-in-webhook-payload
Correct card URL in comment JSON output
2026-02-17 17:20:02 +00:00
Kevin McConnell 4e9773f9f5 Correct card URL in comment JSON output
When rendering details of a comment, we were using the card's `id` as
the param for the URL. But card routes use the card's number, not ID.
2026-02-17 17:11:39 +00:00
Stanko Krtalić 4b2586769b Merge pull request #2556 from basecamp/fix-notifications-staying-unread-on-card-visit
Reinstate card readings
2026-02-17 14:15:24 +01:00
Stanko K.R. 9d4db14fc3 Reinstate card readings 2026-02-17 13:57:24 +01:00
Alp Keser 13d7cd4303 Paginate boards JSON 2026-02-17 10:37:23 +03:00
dependabot[bot] 38ff89de09 Bump bootsnap from 1.21.1 to 1.22.0 (#2544)
* Bump bootsnap from 1.21.1 to 1.22.0

Bumps [bootsnap](https://github.com/rails/bootsnap) from 1.21.1 to 1.22.0.
- [Release notes](https://github.com/rails/bootsnap/releases)
- [Changelog](https://github.com/rails/bootsnap/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rails/bootsnap/compare/v1.21.1...v1.22.0)

---
updated-dependencies:
- dependency-name: bootsnap
  dependency-version: 1.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-16 16:09:22 -08:00
Jeremy Daer a253c31dee Batch webhook delivery cleanup to prevent DB lock contention (#2555)
Follow-up to #2550 which added a created_at index and increased cleanup
frequency. The delete itself was still unbatched and vulnerable whenever
a backlog accumulates (first run after deploy, clock skew, etc).

Delete in small batches with a pause between each to let other
transactions through, following the SolidQueue pattern.
2026-02-16 15:31:10 -08:00
dependabot[bot] 0ead67f85b Bump the development-dependencies group across 1 directory with 3 updates (#2546)
* Bump the development-dependencies group across 1 directory with 3 updates

Bumps the development-dependencies group with 3 updates in the / directory: [brakeman](https://github.com/presidentbeef/brakeman), [faker](https://github.com/faker-ruby/faker) and [selenium-webdriver](https://github.com/SeleniumHQ/selenium).


Updates `brakeman` from 7.1.2 to 8.0.1
- [Release notes](https://github.com/presidentbeef/brakeman/releases)
- [Changelog](https://github.com/presidentbeef/brakeman/blob/main/CHANGES.md)
- [Commits](https://github.com/presidentbeef/brakeman/compare/v7.1.2...v8.0.1)

Updates `faker` from 3.5.3 to 3.6.0
- [Release notes](https://github.com/faker-ruby/faker/releases)
- [Changelog](https://github.com/faker-ruby/faker/blob/main/CHANGELOG.md)
- [Commits](https://github.com/faker-ruby/faker/compare/v3.5.3...v3.6.0)

Updates `selenium-webdriver` from 4.39.0 to 4.40.0
- [Release notes](https://github.com/SeleniumHQ/selenium/releases)
- [Changelog](https://github.com/SeleniumHQ/selenium/blob/trunk/rb/CHANGES)
- [Commits](https://github.com/SeleniumHQ/selenium/compare/selenium-4.39.0...selenium-4.40.0)

---
updated-dependencies:
- dependency-name: brakeman
  dependency-version: 8.0.1
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: development-dependencies
- dependency-name: faker
  dependency-version: 3.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: selenium-webdriver
  dependency-version: 4.40.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* Auto-sync Gemfile.saas.lock on Dependabot PRs

Dependabot can't update custom-named Gemfiles, so Gemfile.saas.lock
drifts whenever it bumps shared gems in Gemfile.lock.

Add `bin/bundle-drift forward` to push oss lockfile changes into the
saas lockfile (the reverse of `correct`), and a GitHub Actions workflow
that runs it automatically on Dependabot bundler branches.

* Update brakeman ignore fingerprint for 8.0.1

Brakeman 8.0.1 changed how it computes warning fingerprints, so the
existing ignore entry for the safe_constantize warning in Notifier
became obsolete. Update to the new fingerprint.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jeremy Daer <jeremy@37signals.com>
2026-02-16 15:29:51 -08:00
Jeremy Daer bc76633f77 Reduce webhook delivery cleanup impact (#2550)
* Add index on webhook_deliveries.created_at

The stale scope (WHERE created_at < ?) and ordered scope
(ORDER BY created_at DESC) both benefit from this index.
Without it, Webhook::Delivery.cleanup does a full table scan.

* Run webhook delivery cleanup every 15 minutes

Each run now deletes ~15 minutes of newly-stale records instead
of ~4 hours worth, a 16x reduction in per-run write volume.
2026-02-16 14:28:05 -08:00
Adrien Maston a1e96670ce Merge pull request #2524 from basecamp/mobile/fix-card-perma-footer
Mobile / Fix card perma footer
2026-02-16 17:39:22 +01:00
Adrien Maston 910500eaf6 Merge pull request #2520 from basecamp/mobile/fix-truncated-card-header
Mobile / Fix truncated card header
2026-02-16 17:38:36 +01:00
Andy Smith eee93cb17d Merge pull request #2553 from basecamp/apostrophe-fix
Use the correct apostrophe character
2026-02-16 10:12:50 -06:00
Andy Smith c41e5aa981 Merge pull request #2437 from nqst/dialog-ux-improvements
Modal dialogs: smoother animations and QR code dialog improvements
2026-02-16 10:12:30 -06:00
Andy Smith 26c380448b Use the correct apostrophe character 2026-02-16 10:03:53 -06:00
Andy Smith edb2f91bbb Merge pull request #2451 from nqst/fix-safari-glitches
Fix Safari transition glitches
2026-02-16 09:58:26 -06:00
Andy Smith b638998789 Merge pull request #2456 from nqst/qr-code-in-dark-mode
Improve QR code appearance in dark mode
2026-02-16 09:54:54 -06:00
Rosa Gutierrez 95114b1d67 Fix race condition between concurrent Event and Mention notifier jobs
When concurrent NotifyRecipientsJobs process an Event and a Mention for
the same user+card, Rails' dirty tracking can skip writing source_type
in the UPDATE if it hasn't changed from the stale in-memory value,
leaving source_type and source_id mismatched (e.g. source_type='Event'
with a Mention's source_id, resulting in a nil source).

Force source_type to always be included in the UPDATE via
source_type_will_change! to prevent this.

Here's a sample timeline of this race condition happening in the real
world (with simplified IDs):

Two `NotifyRecipientsJob` involving notification `03fklpu`, same card,
same user, same comment — enqueued within 50ms of each other:

1. Both jobs load notification `03fklpu` — it has source_type='Mention'
   (from a previous job)
2. `EventNotifier` writes at 21:22:36.051: ```sql SET
   source_type='Event', source_id=<event_id>, unread_count=1 ```
3. `source_type` included because it changed ('Mention' → 'Event')
4. `MentionNotifier` writes at 21:22:36.057 (~6ms later): ```sql SET
   source_id=<mention_id>, unread_count=1 ```
5. No `source_type`! It was `'Mention'` when loaded and `'Mention'` is
   what it's setting → not dirty → skipped
6. Final DB state: `source_type='Event'` (from step 2, untouched),
   `source_id=<mention_id>` (from step 3)

`Notification.source` now does `Event.find(<mention_id>) → nil.`

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:50:46 +01:00
Andy Smith bee16f5f9c Merge pull request #2548 from nqst/fix-notifications-typography
Push notification section typography fixes
2026-02-16 09:45:42 -06:00
Andy Smith d31756fed3 Merge pull request #2549 from basecamp/fix-typo
Fix typo
2026-02-16 09:41:03 -06:00
Alp Keser a48c88cb5d Stabilize notifications tray test ordering via fixture updated_at timestamps 2026-02-16 18:33:32 +03:00
Alp Keser bcc0f93bb9 Preload notification card associations used by JSON responses 2026-02-16 17:58:33 +03:00
Rosa Gutierrez b742963f7c Add account ownership check to import GID resolution
The convert_gids_to_sgids method resolved GIDs globally and minted
valid SGIDs without verifying the record belongs to the importing
account. This adds the same account_id check that the export path
already has, plus RecordNotFound handling for invalid GIDs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 11:49:00 +01:00
Andy Smith 1572e70b65 Fix typo 2026-02-13 17:45:58 -06:00
Andy Smith f2bf7c7460 Merge pull request #2547 from basecamp/import-export-clarification
Import export clarification
2026-02-13 17:40:35 -06:00
Alexander Zaytsev bef5bb60c9 Target correct selector 2026-02-14 00:17:16 +01:00
Alexander Zaytsev 635ef4fbe5 Fix paragraph rendering as an inline element 2026-02-14 00:02:56 +01:00
Andy Smith d7814792e3 Tweak language 2026-02-13 15:17:33 -06:00
Alexander Zaytsev 6f839c5b2f Remove periods after ellipses 2026-02-13 18:21:47 +01:00
Alexander Zaytsev da5e67a0a6 Use h3 instead of h2 2026-02-13 18:19:38 +01:00
David Heinemeier Hansson f0583888eb More missing dependencies for libvips 2026-02-13 17:47:30 +01:00
David Heinemeier Hansson d7a10bea1c Include missing vips dependencies 2026-02-13 17:40:08 +01:00
Adrien Maston e3edb98465 Merge branch 'main' into mobile/fix-card-perma-footer
* main: (33 commits)
  Revert "Add temporary performance degradation message"
  Fix double-escaped HTML entities in webhook payloads
  Fix crash when a notification is deleted while a bundle is being sent
  Fix race condition on notification creation
  Fix double _seconds suffix in GVL request wait metric name (#2539)
  Add GVL contention metrics via gvltools (#2538)
  Backfill tests for Event::Description strings' html-safety
  Update copy
  Add temporary performance degradation message
  Render inline code in card titles (#2518)
  Add stackprof for profiling
  Table style tweaks
  Fix dark mode colors
  Index notifications on updated_at
  Stack notifications everywhere
  HR fixes
  Removing duplicate code language picker
  Regression fixes
  Touch up link button hover styles
  Remove link dialog size limit
  ...
2026-02-13 15:44:01 +01:00
Mike Dalessio dc492ef17e Merge pull request #2540 from basecamp/fix-quotes
Fix double-escaped HTML entities in basecamp and campfire webhook payloads
2026-02-13 09:26:00 -05:00
Adrien Maston 6bacbdce78 Fix trailing margin depending on boosts 2026-02-13 12:17:36 +01:00
Adrien Maston 61489593b9 Re-align all the rows 2026-02-13 12:02:26 +01:00
Samuel Péchèr ab0320b9f5 Merge pull request #2542 from basecamp/remove-performance-notice
Revert "Add temporary performance degradation message"
2026-02-13 10:10:00 +00:00
Samuel Péchèr 0ab88af118 Revert "Add temporary performance degradation message"
This reverts commit 2a1f9cd15b.
2026-02-13 10:05:22 +00:00
Stanko Krtalić 7ce88b5d7e Merge pull request #2541 from basecamp/notification-fixes
Fix race conditions with notifications
2026-02-13 09:45:23 +01:00
Mike Dalessio 0c10622672 Fix double-escaped HTML entities in webhook payloads
`Event::Description#to_plain_text` now returns an html-safe string to
prevent double-escaping when the ERB template renders the basecamp
and campfire payloads.

ref: https://3.basecamp.com/2914079/buckets/27/card_tables/cards/9574495379
2026-02-13 03:25:59 -05:00
Stanko K.R. 05042ed54a Fix crash when a notification is deleted while a bundle is being sent 2026-02-13 09:22:51 +01:00
Stanko K.R. ae3d277868 Fix race condition on notification creation 2026-02-13 09:14:24 +01:00
Jeremy Daer 231db6e742 Fix double _seconds suffix in GVL request wait metric name (#2539)
Rename histogram from :request_wait_seconds to :request_wait so Yabeda's
unit: :seconds produces gvl_request_wait_seconds instead of
gvl_request_wait_seconds_seconds.
2026-02-12 16:41:20 -08:00
Jeremy Daer a5a5a62169 Add GVL contention metrics via gvltools (#2538)
* Add GVL contention metrics via gvltools and Yabeda

Expose per-request and process-wide GVL wait time as Prometheus metrics
to diagnose suspected GVL contention from Solid Cable and Action Cable
threads in Puma workers.

Metrics: gvl_request_wait_seconds (histogram), gvl_waiting_threads
(gauge), gvl_global_timer_total_seconds (gauge).

* Add unit: :seconds to GVL histogram for consistency
2026-02-12 16:28:29 -08:00
Jirka Hutárek c4c46cce44 Add postponed and closed flags to Pinned and Notification cards 2026-02-13 00:45:47 +01:00
Mike Dalessio 4ead778e12 Backfill tests for Event::Description strings' html-safety 2026-02-12 15:52:56 -05:00
Andy Smith 8aa934a594 Merge pull request #2534 from basecamp/copy-fix
Update copy
2026-02-12 12:16:00 -06:00