Commit Graph

9336 Commits

Author SHA1 Message Date
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
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
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
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
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
Andy Smith f77850f5be Update copy 2026-02-12 12:13:05 -06:00
Andy Smith c6b24e9713 Merge pull request #2533 from basecamp/slow-message
Add temporary performance degradation message
2026-02-12 12:04:33 -06:00
Andy Smith 2a1f9cd15b Add temporary performance degradation message 2026-02-12 12:01:18 -06:00
Mike Dalessio 851f13a934 Render inline code in card titles (#2518)
* Remove unused marked JS dependency

* Remove unused redcarpet dependency

* Render inline code in card titles

Add card_html_title helper that HTML-escapes input then converts
backtick-wrapped text to <code> elements. Apply to card titles in
board preview, card detail, public views, and notification emails.
Style inline code elements in titles to match description styling.

Co-authored-by: Andy Smith <andy@37signals.com>

---------

Co-authored-by: Andy Smith <andy@37signals.com>
2026-02-12 12:07:40 -05:00
Adrien Maston 486da76a26 Merge pull request #2497 from basecamp/mobile/fix-stage-button-gap 2026-02-12 18:03:55 +01:00
Adrien Maston 8f924bd5d4 Merge pull request #2494 from basecamp/mobile/fix-truncated-comment-dates 2026-02-12 18:03:39 +01:00
Adrien Maston 07dfeedb7d Merge pull request #2521 from basecamp/mobile/tweak-card-draft-ui 2026-02-12 18:03:14 +01:00
Donal McBreen a690fa59e5 Merge pull request #2532 from basecamp/add-stackprof
Add stackprof for profiling
2026-02-12 16:06:45 +00:00
Donal McBreen 1506624cd3 Add stackprof for profiling
So you can do something like this:

```ruby
  require "stackprof"

  report = StackProf.run(mode: :wall, interval: 100) do
    Account.find_by(external_account_id: 123)
  end

  StackProf::Report.new(report).print_text
```
2026-02-12 15:42:50 +00:00
Zoltán Hosszú ee4511180a Merge pull request #2529 from basecamp/lexxy-dark-mode-fix
- Fix dark mode colors
- Table style tweaks
2026-02-12 11:50:17 +01:00
Zoltan Hosszu 135fe128f7 Table style tweaks 2026-02-12 11:46:04 +01:00
Stanko Krtalić 17a545fffa Merge pull request #2530 from basecamp/notification-sorting-optimization
Index notifications on updated_at
2026-02-12 11:41:36 +01:00
Zoltan Hosszu ff80dfeb06 Fix dark mode colors 2026-02-12 11:37:08 +01:00
Stanko K.R. 22276a25c8 Index notifications on updated_at
As we now update notifications with unread counts we sort them by the
time they were updated instead of when they were created. To keep that
performant we also have to change the previous indices that used
created_at to use updated_at.
2026-02-12 11:36:46 +01:00
Stanko Krtalić 61144667fc Merge pull request #2512 from basecamp/server-side-notification-grouping
Stack notifications in all views
2026-02-12 10:33:12 +01:00
Stanko K.R. 36ee253a1a Stack notifications everywhere
We had client-side notification stacking in the tray since launch, but now we want to stack notifications in the notifications page, in API responses and in email bundles.
2026-02-12 10:29:50 +01:00
Zoltán Hosszú 446c75bb5c Merge pull request #2457 from basecamp/lexxy-version-bump
- Bump Lexxy's version to latest 0.7.4
- Enable tables with the recent UX enhancements
- Use Lexxy's built-in CSS for rich text rendering, removing the duplicate CSS from Fizzy
2026-02-12 10:04:10 +01:00
Zoltan Hosszu e0f8a182c5 HR fixes 2026-02-12 09:54:21 +01:00
Zoltan Hosszu 343bf016a3 Removing duplicate code language picker 2026-02-12 09:54:21 +01:00
Zoltan Hosszu 9a2e30b9c8 Regression fixes 2026-02-12 09:54:21 +01:00
Andy Smith 322de4217f Touch up link button hover styles 2026-02-12 09:54:21 +01:00