Commit Graph

9423 Commits

Author SHA1 Message Date
Adrien Maston bf98b1a6d7 Adjust closed stamp position on perma 2026-02-24 12:44:13 +01:00
Adrien Maston 73068bc2cf Restrict top positioning of closed stamp to perma 2026-02-23 12:42:02 +01:00
Adrien Maston 5c7b3a8acb Keep reactions in static positioning on card perma
... and remove no longer needed styles
2026-02-23 12:41:38 +01:00
Jeremy Daer a02042b4c5 Add Deploy section to AGENTS.md (#2593)
* AGENTS.md: add Deploy section (main, 7 destinations, saas:enable)

Structured format for agent prelude discovery and cross-app
drift checking via verify-app-registry.

* Address review: document beta template env var requirement

The beta deploy config requires BETA_NUMBER; typical targets are beta1-beta4.
2026-02-22 11:04:33 -08:00
Peter Berkenbosch 8a591bd8ee Fix typos in AGENTS.md (#2571) 2026-02-21 23:13:01 -05:00
Fernando 8d2075b653 Merge pull request #2580 from basecamp/fix-hyphenated-search
Fix hyphenated search
2026-02-20 12:14:38 -06:00
Andy Smith b8c4b4a609 Merge pull request #2586 from basecamp/profile-center
Use flex instead of grid to better support single sections
2026-02-20 12:09:00 -06:00
Andy Smith cd80893957 Handle two column layout on mobile 2026-02-20 11:55:36 -06:00
Andy Smith dc0452fd0e Use flex instead of grid to better support single sections 2026-02-20 11:54:16 -06:00
Andy Smith 25adfbbcb0 Merge pull request #2584 from basecamp/settings-overflow-fix
Make generic scrollable list class for settings
2026-02-20 11:47:31 -06:00
Rosa Gutierrez 3e5233239b Fix push notification not firing on notification creation
- Rails only applies the last callback when `after_create_commit` and
  `after_update_commit` reference the same method name [1]:

> However, if you use the `after_create_commit` and the
`after_update_commit` callback with the same method name, it will only
allow the last callback defined to take effect, as they both internally
alias to `after_commit` which overrides previously defined callbacks
with the same method name.

- Push notifications were never sent when a notification was first
  created — only when the source was updated
- Replaced the two callbacks with a single `after_save_commit`, which
  fires on both create and update, with the
  `source_id_previously_changed?` guard (true for both new records and
  source changes)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

[1] https://guides.rubyonrails.org/active_record_callbacks.html#aliases-for-after-commit
2026-02-20 18:37:33 +01:00
Andy Smith 17d869cf08 Cleanup unused classes 2026-02-20 11:09:15 -06:00
Andy Smith f835c211af Make generic scrollable list class for settings 2026-02-20 11:05:26 -06:00
Rosa Gutierrez bb6f2963b4 Revert commits accidentally pushed to main
Revert "Add bridged share button to board and card permas"
This reverts commit 069e165b43.

Revert "Move helper to bridge helper file"
This reverts commit 1ee37f046c.
2026-02-20 12:58:39 +01:00
Adrien Maston 069e165b43 Add bridged share button to board and card permas 2026-02-20 12:49:00 +01:00
Adrien Maston 1ee37f046c Move helper to bridge helper file 2026-02-20 12:46:00 +01:00
Fernando Olivares 85dc8ba455 Add repeated punctuation search stemmer test 2026-02-19 16:23:26 -06:00
Fernando Olivares 3932fce309 Add tests for hyphenated string search
Cover the stemmer tokenizing hyphenated input into separate words and
end-to-end search finding cards with hyphenated titles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 16:16:44 -06:00
Fernando Olivares 554182f4b4 Fix stemmer stripping hyphens instead of splitting on them
The stemmer was concatenating tokens across hyphens (e.g. "BC3-IOS-1D8B"
→ "bc3ios1d8b") while the query sanitizer split on them, causing MySQL
MATCH AGAINST to never find the indexed token. Replace non-word chars
with spaces instead of stripping them so indexing and querying tokenize
consistently.

Requires search:reindex after deploy to rebuild existing search records.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 16:16:39 -06:00
Adrien Maston 2bf9d92a03 Merge pull request #2578 from basecamp/mobile/tweak-page-header 2026-02-19 19:04:38 +01:00
Adrien Maston 92a845b17b Remove additional space above header
... to align with native titles
2026-02-19 17:54:02 +01:00
Adrien Maston 0394c44f22 Merge pull request #2577 from basecamp/fix-unpin-typo
Fix "Unpin" typo
2026-02-19 16:53:29 +01:00
Adrien Maston 904917f648 Up-pin should be Unpin 2026-02-19 16:36:32 +01:00
Zoltán Hosszú 10875bc2ee Merge pull request #2576 from basecamp/editor-fixes
Small editor fixes
2026-02-19 16:28:49 +01:00
Zoltan Hosszu b248183b54 Fixed extra padding in mentions dropdown 2026-02-19 16:25:52 +01:00
Zoltan Hosszu 9c01434f68 Fixed missing attachment selection outline 2026-02-19 16:25:41 +01:00
Adrien Maston c2d5070840 Merge pull request #2567 from basecamp/mobile/fix-empty-search 2026-02-19 14:28:54 +01:00
Adrien Maston 5f25ebe3f4 Add a line break, it looks better 2026-02-19 14:25:26 +01:00
Adrien Maston f2fb05cecf Replace unless by if 2026-02-19 14:09:48 +01:00
Adrien Maston 97f2f677d6 Don't render empty state instead of hiding it 2026-02-19 14:04:14 +01:00
Adrien Maston 542777409c Add test 2026-02-19 12:07:08 +01:00
Adrien Maston 0e1feb0f3f Create @query in controller instead of testing for blank? 2026-02-19 12:06:49 +01:00
Jeremy Daer 953942694f Handle MissingEOCD as invalid zip file, not job failure (#2572)
ZipKit::FileReader raises MissingEOCD for truncated, corrupted, or
non-zip files. This exception is a direct StandardError subclass, not
a subclass of InvalidStructure or ReadError, so it escaped as an
unhandled job failure instead of being caught and surfaced to the user.

Broaden the rescue in ZipFile::Reader#initialize to catch ReadError
(parent of InvalidStructure), MissingEOCD, and UnsupportedFeature.
2026-02-18 15:18:56 -08:00
Mike Dalessio 352199785e Merge pull request #2570 from basecamp/upgrade-rails-20260218
Update Rails to 12e24ea (363 commits)
2026-02-18 15:42:15 -05:00
Mike Dalessio 3b229e9aab Pin web-console to GitHub main for Rails compatibility
web-console 4.2.1 overrides the now-renamed filter_proxies method in
ActionDispatch::RemoteIp::GetIp. The fix (rails/web-console#344) is on
main but not yet released.
2026-02-18 15:16:21 -05:00
Jeremy Daer ed81ca760f Restore unique index on board_publications.key (#2568)
* Restore unique index on board_publications.key

The account_id rollout (fe6df7085) replaced the unique index on
board_publications.key with a non-unique composite (account_id, key)
index. This was unintentional — other tables in the same migration
preserved uniqueness (account_join_codes, tags) but this one did not.

Without global uniqueness on key, a crafted data import can insert a
duplicate publication key via insert_all! (which bypasses model
validations). Since find_by_published_key queries globally without
account scoping, this enables public board URL hijacking after the
legitimate owner unpublishes.

Restore the original unique index on key and keep a plain account_id
index for account-scoped queries.

* Reorder index operations: add unique index before dropping composite

On MySQL, DDL is non-transactional. If the unique index creation
fails (e.g. duplicate keys exist), the previous ordering would leave
the composite index already dropped. Adding the unique index first
means a failure leaves the database unchanged.

* Add schema dumps for both SQLite and MySQL

Dump both schema files after running the migration against each
adapter to keep the PR complete for CI.
2026-02-18 11:21:25 -08:00
Jeremy Daer 2d7950879d Normalize schema_sqlite.rb to reflect TableDefinitionColumnLimits initializer (#2569)
The table_definition_column_limits initializer (PR #1669) applies a
default limit of 255 to all string columns during schema:load, but
schema_sqlite.rb was never re-dumped after it landed. This caused
drift on every subsequent migration PR that dumped the schema.

Re-dump from schema:load → schema:dump to make the file idempotent.
2026-02-18 11:13:13 -08:00
Mike Dalessio 41675224d0 Remove redundant insecure context CSRF check
Rails now handles the insecure context case natively in
verified_via_header_only? — when Sec-Fetch-Site is missing and the
request is plain HTTP without force_ssl, the request is allowed.

Remove the now-redundant allowed_insecure_context_request? method and
update the test to set ActionDispatch::Http::URL.secure_protocol
alongside Rails.configuration.force_ssl so the upstream check works
correctly in the test environment.
2026-02-18 14:06:46 -05:00
Mike Dalessio 41c2bd38af Update Rails to 12e24ea (363 commits past 60d92e4)
Also updates transitive dependencies:
- action_text-trix ~> 2.1.15 → ~> 2.1.16
- irb 1.16.0 → 1.17.0
- json 2.18.0 → 2.18.1
- net-imap 0.6.2 → 0.6.3
- nokogiri 1.19.0 → 1.19.1
- prism 1.8.0 → 1.9.0
- rack 3.2.4 → 3.2.5
- rdoc 7.0.3 → 7.2.0
2026-02-18 13:37:13 -05:00
Mike Dalessio 1c3b3c55ef Update rails_structured_logging to v0.3.0
v0.3.0 removes usage of the INTERNAL_PARAMS constant which is being
removed from ActionController in an upcoming Rails upgrade.
2026-02-18 13:33:10 -05:00
Jeremy Daer f39253e5f9 Remove defunct saas/Gemfile and lockfile (#2566)
These are leftovers from when fizzy-saas was a standalone repository.
Since it was moved into fizzy as a path gem, the production bundle
uses Gemfile.saas at the root. Nothing references saas/Gemfile.

Also removes saas/bin/rails (references nonexistent test/dummy app)
and saas/bin/rubocop (references nonexistent saas/.rubocop.yml),
both equally defunct standalone-repo leftovers.
2026-02-18 09:27:28 -08:00
Adrien Maston 5c0508d91c Don't show "no match" when not searching anything yet 2026-02-18 18:19:37 +01:00
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