From fa4e77f35e6193fa2ad49d95344a7e2225e4c37b Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Mon, 19 Jan 2026 20:46:49 +0100 Subject: [PATCH 01/10] Prevent page scrolling when modal dialog is open --- app/assets/stylesheets/dialog.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/assets/stylesheets/dialog.css b/app/assets/stylesheets/dialog.css index 5d6a7eb0e..16bc7a4ec 100644 --- a/app/assets/stylesheets/dialog.css +++ b/app/assets/stylesheets/dialog.css @@ -1,4 +1,9 @@ @layer components { + /* Prevent page scrolling when modal dialog is open */ + html:has(dialog:modal) { + overflow: hidden; + } + :is(.dialog) { border: 0; opacity: 0; From aea90f4b5088a1eee1cffda00e453945cb303300 Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Tue, 20 Jan 2026 10:40:04 +0100 Subject: [PATCH 02/10] Add viewport padding to dialogs on mobile --- app/assets/stylesheets/dialog.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/assets/stylesheets/dialog.css b/app/assets/stylesheets/dialog.css index 5d6a7eb0e..632d9af74 100644 --- a/app/assets/stylesheets/dialog.css +++ b/app/assets/stylesheets/dialog.css @@ -35,4 +35,11 @@ } } } + + /* Ensure padding from viewport edges on narrow screens */ + @media (max-width: 639px) { + .dialog.panel { + max-inline-size: 94vw; + } + } } From aba88cdc3ff66293f0c8c843165a51de80cc14ef Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Tue, 20 Jan 2026 10:40:29 +0100 Subject: [PATCH 03/10] Use CSS variable for panel size in delete dialogs --- app/views/boards/edit/_delete.html.erb | 2 +- app/views/cards/_delete.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/boards/edit/_delete.html.erb b/app/views/boards/edit/_delete.html.erb index ec346f590..9d9b7f441 100644 --- a/app/views/boards/edit/_delete.html.erb +++ b/app/views/boards/edit/_delete.html.erb @@ -3,7 +3,7 @@ <%= icon_tag "trash" %> Delete this board - +

Delete this board?

Are you sure you want to permanently delete this board and all the cards on it? This can't be undone.

diff --git a/app/views/cards/_delete.html.erb b/app/views/cards/_delete.html.erb index 43afbbad2..e6b999ee0 100644 --- a/app/views/cards/_delete.html.erb +++ b/app/views/cards/_delete.html.erb @@ -3,7 +3,7 @@ <%= icon_tag "trash" %> Delete this card - +

Delete this card?

Are you sure you want to permanently delete this card?

From bfea02ebd0cf3a107afd70b472ea1b75623f7359 Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Tue, 20 Jan 2026 10:54:39 +0100 Subject: [PATCH 04/10] Actually make it affect larger screens too And remove a magic number --- app/assets/stylesheets/dialog.css | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/dialog.css b/app/assets/stylesheets/dialog.css index 632d9af74..75f03136a 100644 --- a/app/assets/stylesheets/dialog.css +++ b/app/assets/stylesheets/dialog.css @@ -36,10 +36,8 @@ } } - /* Ensure padding from viewport edges on narrow screens */ - @media (max-width: 639px) { - .dialog.panel { - max-inline-size: 94vw; - } + /* Ensure padding from viewport edges */ + .dialog.panel { + max-inline-size: calc(100vw - var(--block-space-double)); } } From 73cf1dede491b7e5afa4a3ae9f3994d02c5d79ff Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Tue, 20 Jan 2026 20:51:01 +0100 Subject: [PATCH 05/10] Use inline spacing variable --- app/assets/stylesheets/dialog.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/dialog.css b/app/assets/stylesheets/dialog.css index 75f03136a..4e10ccabb 100644 --- a/app/assets/stylesheets/dialog.css +++ b/app/assets/stylesheets/dialog.css @@ -38,6 +38,6 @@ /* Ensure padding from viewport edges */ .dialog.panel { - max-inline-size: calc(100vw - var(--block-space-double)); + max-inline-size: calc(100vw - var(--inline-space-double) * 2); } } From 468fe5f16b4c40bcb31803fcfe5d183f4fea6c28 Mon Sep 17 00:00:00 2001 From: Kevin McConnell Date: Wed, 21 Jan 2026 09:42:44 +0000 Subject: [PATCH 06/10] Only index up to 32KB of search content To prevent overflowing the columns in the search index tables (and also just to avoid creating massive indexes), let's limit the searchable content to the first 32KB. --- app/models/concerns/searchable.rb | 8 +++++++- test/models/card/searchable_test.rb | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/models/concerns/searchable.rb b/app/models/concerns/searchable.rb index 8b39504ef..17d1f186a 100644 --- a/app/models/concerns/searchable.rb +++ b/app/models/concerns/searchable.rb @@ -1,6 +1,8 @@ module Searchable extend ActiveSupport::Concern + SEARCH_CONTENT_LIMIT = 32.kilobytes + included do after_create_commit :create_in_search_index after_update_commit :update_in_search_index @@ -32,11 +34,15 @@ module Searchable card_id: search_card_id, board_id: search_board_id, title: search_title, - content: search_content, + content: search_record_content, created_at: created_at } end + def search_record_content + search_content&.truncate_bytes(SEARCH_CONTENT_LIMIT, omission: "") + end + def search_record_class Search::Record.for(account_id) end diff --git a/test/models/card/searchable_test.rb b/test/models/card/searchable_test.rb index d6dcdf60c..5c7ca9c86 100644 --- a/test/models/card/searchable_test.rb +++ b/test/models/card/searchable_test.rb @@ -32,6 +32,24 @@ class Card::SearchableTest < ActiveSupport::TestCase assert_not_includes results, card_in_other_board end + test "search content is truncated to a reasonable limit" do + search_record_class = Search::Record.for(@user.account_id) + + # Create a card with unreasonably long content + long_content = "asdf " * Searchable::SEARCH_CONTENT_LIMIT + card = @board.cards.create!(title: "Card with long description", creator: @user) + card.description = ActionText::Content.new(long_content) + card.save! + + # Check if was indexed + results = Card.mentioning("asdf", user: @user) + assert_includes results, card + + # Check the content length was within the limit + search_record = search_record_class.find_by(searchable_type: "Card", searchable_id: card.id) + assert search_record.content.bytesize <= Searchable::SEARCH_CONTENT_LIMIT + end + test "deleting card removes search record and FTS entry" do search_record_class = Search::Record.for(@user.account_id) card = @board.cards.create!(title: "Card to delete", creator: @user) From 783faf3c955c4df12db5b112a4f09f88ba8ea7c1 Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Wed, 21 Jan 2026 11:03:04 -0800 Subject: [PATCH 07/10] Make the CLAUDE.md stub less obtrusive (Until Claude supports AGENTS.md natively, we need to keep the stub.) --- .claude/CLAUDE.md | 1 + CLAUDE.md | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 .claude/CLAUDE.md delete mode 100644 CLAUDE.md diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 100644 index 000000000..dba71e970 --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1 @@ +@../AGENTS.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 43c994c2d..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -@AGENTS.md From eccef3b19cbc12bcb354a23b48b451e06db72ecd Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Wed, 21 Jan 2026 14:33:19 -0600 Subject: [PATCH 08/10] Only submit on blur if the input has a value --- app/javascript/controllers/form_controller.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/javascript/controllers/form_controller.js b/app/javascript/controllers/form_controller.js index beca1f08f..2ba58ab89 100644 --- a/app/javascript/controllers/form_controller.js +++ b/app/javascript/controllers/form_controller.js @@ -54,6 +54,10 @@ export default class extends Controller { } submitToTopTarget(event) { + const value = event.target.value?.trim() + + if (!value) return false + this.element.setAttribute("data-turbo-frame", "_top") this.submit() } From 6c8d333bc94fab62ed0fbfef5a31a8c28993d060 Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Wed, 21 Jan 2026 14:35:30 -0600 Subject: [PATCH 09/10] Bump card perma z-index when dialog is open --- app/assets/stylesheets/card-perma.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/card-perma.css b/app/assets/stylesheets/card-perma.css index d3b671b9a..e68706765 100644 --- a/app/assets/stylesheets/card-perma.css +++ b/app/assets/stylesheets/card-perma.css @@ -25,7 +25,7 @@ position: relative; &:has(dialog[open]) { - z-index: 2; + z-index: 3; } &:has(.card-perma__star-input:checked) { From f9f638a9a7d90aa5afb3152e71a688ade944d31a Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Wed, 21 Jan 2026 15:05:47 -0600 Subject: [PATCH 10/10] Return to Board page when clearing filters --- app/views/filters/settings/_manage.html.erb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/filters/settings/_manage.html.erb b/app/views/filters/settings/_manage.html.erb index ef800df72..11b351709 100644 --- a/app/views/filters/settings/_manage.html.erb +++ b/app/views/filters/settings/_manage.html.erb @@ -1,7 +1,8 @@ <% filter = user_filtering.filter %> +<% clear_url = filter.single_board ? board_path(filter.single_board) : no_filtering_url %>
- <%= link_to no_filtering_url, class: "btn btn--remove txt-x-small", data: { controller: "hotkey tooltip", action: "keydown.esc@document->hotkey#click"} do %> + <%= link_to clear_url, class: "btn btn--remove txt-x-small", data: { controller: "hotkey tooltip", action: "keydown.esc@document->hotkey#click"} do %> <%= icon_tag "close" %> Clear all <% end %>