From bb54b859dcb1507bea4820ab5eb9551311030766 Mon Sep 17 00:00:00 2001 From: Rob Zolkos Date: Tue, 14 Apr 2026 13:14:14 -0400 Subject: [PATCH] Add workflow column filtering to cards (#2787) --- app/models/filter.rb | 1 + app/models/filter/fields.rb | 10 +++++++++- app/models/filter/params.rb | 1 + docs/api/sections/cards.md | 6 ++++++ test/controllers/cards_controller_test.rb | 14 ++++++++++++++ test/models/filter_test.rb | 11 +++++++++++ 6 files changed, 42 insertions(+), 1 deletion(-) diff --git a/app/models/filter.rb b/app/models/filter.rb index 9bfefe176..ab302fc1d 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -35,6 +35,7 @@ class Filter < ApplicationRecord result = terms.reduce(result) do |result, term| result.mentioning(term, user: creator) end + result = result.where(column_id: column_ids) if column_ids.present? result.distinct end diff --git a/app/models/filter/fields.rb b/app/models/filter/fields.rb index 0e1c62e0a..a41d5ce4a 100644 --- a/app/models/filter/fields.rb +++ b/app/models/filter/fields.rb @@ -31,7 +31,7 @@ module Filter::Fields included do store_accessor :fields, :assignment_status, :indexed_by, :sorted_by, :terms, - :card_ids, :creation, :closure + :card_ids, :creation, :closure, :column_ids def assignment_status super.to_s.inquiry @@ -60,6 +60,14 @@ module Filter::Fields def terms=(value) super(Array(value).filter(&:present?)) end + + def column_ids + Array(super).filter(&:present?).uniq + end + + def column_ids=(value) + super(Array(value).filter(&:present?).uniq) + end end def with(**fields) diff --git a/app/models/filter/params.rb b/app/models/filter/params.rb index 586a75885..c93497035 100644 --- a/app/models/filter/params.rb +++ b/app/models/filter/params.rb @@ -8,6 +8,7 @@ module Filter::Params :creation, :closure, card_ids: [], + column_ids: [], assignee_ids: [], creator_ids: [], closer_ids: [], diff --git a/docs/api/sections/cards.md b/docs/api/sections/cards.md index 223578884..f71a75246 100644 --- a/docs/api/sections/cards.md +++ b/docs/api/sections/cards.md @@ -16,6 +16,7 @@ __Query Parameters:__ | `creator_ids[]` | Filter by card creator ID(s) | | `closer_ids[]` | Filter by user ID(s) who closed the cards | | `card_ids[]` | Filter to specific card ID(s) | +| `column_ids[]` | Filter by workflow column ID(s) | | `indexed_by` | Filter by: `all` (default), `closed`, `not_now`, `stalled`, `postponing_soon`, `golden` | | `sorted_by` | Sort order: `latest` (default), `newest`, `oldest` | | `assignment_status` | Filter by assignment status: `unassigned` | @@ -23,6 +24,11 @@ __Query Parameters:__ | `closure` | Filter by closure date: `today`, `yesterday`, `thisweek`, `lastweek`, `thismonth`, `lastmonth`, `thisyear`, `lastyear` | | `terms[]` | Search terms to filter cards | +Repeated `column_ids[]` values are ORed together. Other filters combine with AND. + +Example: +- `column_ids[]=03f...` — cards in a workflow column by ID + __Response:__ ```json diff --git a/test/controllers/cards_controller_test.rb b/test/controllers/cards_controller_test.rb index f582aa9c0..2b51a7cb8 100644 --- a/test/controllers/cards_controller_test.rb +++ b/test/controllers/cards_controller_test.rb @@ -15,6 +15,20 @@ class CardsControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "index as JSON can filter by workflow column id" do + get cards_path(format: :json), params: { column_ids: [ columns(:writebook_in_progress).id ] } + assert_response :success + + assert_equal [ cards(:text).number ], @response.parsed_body.pluck("number") + end + + test "index as JSON can OR multiple workflow column ids" do + get cards_path(format: :json), params: { column_ids: [ columns(:writebook_triage).id, columns(:writebook_in_progress).id ] } + assert_response :success + + assert_equal [ cards(:logo).number, cards(:layout).number, cards(:text).number ].sort, @response.parsed_body.pluck("number").sort + end + test "create a new draft" do assert_difference -> { Card.count }, 1 do post board_cards_path(boards(:writebook)) diff --git a/test/models/filter_test.rb b/test/models/filter_test.rb index bb41f3e41..7fb7b6ae3 100644 --- a/test/models/filter_test.rb +++ b/test/models/filter_test.rb @@ -166,6 +166,17 @@ class FilterTest < ActiveSupport::TestCase assert_not users(:david).filters.new(board_ids: [ boards(:writebook).id ]).used?(ignore_boards: true) end + test "column ids filter cards by workflow columns" do + assert_equal [ cards(:text) ], users(:david).filters.new(column_ids: [ columns(:writebook_in_progress).id ]).cards.to_a + assert_equal [ cards(:logo), cards(:layout) ].sort_by(&:id), users(:david).filters.new(column_ids: [ columns(:writebook_triage).id ]).cards.to_a.sort_by(&:id) + end + + test "column ids are ORed together" do + filter = users(:david).filters.new(column_ids: [ columns(:writebook_triage).id, columns(:writebook_in_progress).id ]) + + assert_equal [ cards(:logo), cards(:layout), cards(:text) ].sort_by(&:id), filter.cards.to_a.sort_by(&:id) + end + test "board titles are scoped to creator's account" do # Give mike (initech) access to the board in his account boards(:miltons_wish_list).accesses.grant_to(users(:mike))