Support selecting multiple cards by using a list of numbers (separated by comma, or space)

https://3.basecamp.com/2914079/buckets/37331921/todos/8620236700#__recording_8620273944
This commit is contained in:
Jorge Manrubia
2025-05-07 11:30:44 +02:00
parent dc28f4c9c5
commit 561e9fad0c
7 changed files with 60 additions and 11 deletions
+11
View File
@@ -0,0 +1,11 @@
class Command::FilterCards < Command
store_accessor :data, :card_ids, :params
def title
"Filter cards #{card_ids.join(",")}"
end
def execute
redirect_to cards_path(**params.without("card_ids").merge(card_ids: card_ids))
end
end
+20 -9
View File
@@ -11,14 +11,14 @@ class Command::Parser
command_name, *command_arguments = string.strip.split(" ")
case command_name
when "/assign", "/assignto"
Command::Assign.new(assignee_ids: assignees_from(command_arguments).collect(&:id), card_ids: cards.ids)
when "/close"
Command::Close.new(card_ids: cards.ids, reason: command_arguments.join(" "))
when /^@/
Command::GoToUser.new(user_id: assignee_from(command_name)&.id)
else
search(string)
when "/assign", "/assignto"
Command::Assign.new(assignee_ids: assignees_from(command_arguments).collect(&:id), card_ids: cards.ids)
when "/close"
Command::Close.new(card_ids: cards.ids, reason: command_arguments.join(" "))
when /^@/
Command::GoToUser.new(user_id: assignee_from(command_name)&.id)
else
search(string)
end
end
@@ -37,10 +37,21 @@ class Command::Parser
end
def search(string)
if card = user.accessible_cards.find_by_id(string)
if cards = multiple_cards_from(string)
Command::FilterCards.new(card_ids: cards.ids, params: filter.as_params)
elsif card = user.accessible_cards.find_by_id(string)
Command::GoToCard.new(card_id: card.id)
else
Command::Search.new(query: string, params: filter.as_params)
end
end
def multiple_cards_from(string)
if tokens = string.split(/[\s,]+/).filter { it =~ /\A\d+\z/ }.presence
if tokens.many?
cards = user.accessible_cards.where(id: tokens)
cards.any? ? cards : nil
end
end
end
end
+1
View File
@@ -19,6 +19,7 @@ class Filter < ApplicationRecord
def cards
@cards ||= begin
result = creator.accessible_cards.indexed_by(indexed_by)
result = result.where(id: card_ids) if card_ids.present? && !indexed_by.closed?
result = result.open unless indexed_by.closed?
result = result.by_engagement_status(engagement_status) if engagement_status.present?
result = result.unassigned if assignment_status.unassigned?
+1 -1
View File
@@ -16,7 +16,7 @@ module Filter::Fields
end
included do
store_accessor :fields, :assignment_status, :indexed_by, :terms, :engagement_status
store_accessor :fields, :assignment_status, :indexed_by, :terms, :engagement_status, :card_ids
def assignment_status
super.to_s.inquiry
+3 -1
View File
@@ -5,6 +5,7 @@ module Filter::Params
:assignment_status,
:indexed_by,
:engagement_status,
card_ids: [],
assignee_ids: [],
creator_ids: [],
collection_ids: [],
@@ -40,8 +41,9 @@ module Filter::Params
params[:assignment_status] = assignment_status
params[:terms] = terms
params[:tag_ids] = tags.ids
params[:collection_ids] = collections.ids
params[:collection_ids] = collections.ids
params[:stage_ids] = stages.ids
params[:card_ids] = card_ids
params[:assignee_ids] = assignees.ids
params[:creator_ids] = creators.ids
end.compact_blank.reject(&method(:default_value?))
+21
View File
@@ -0,0 +1,21 @@
require "test_helper"
class Command::FilterCardsTest < ActionDispatch::IntegrationTest
include CommandTestHelper
setup do
@card_ids = cards(:logo, :layout).collect(&:id)
end
test "redirects to the cards index filtering by cards" do
result = execute_command "#{@card_ids.join(" ")}"
assert_equal cards_path(indexed_by: "newest", card_ids: @card_ids), result.url
end
test "respects existing filters" do
result = execute_command "#{@card_ids.join(",")}", context_url: "http://37signals.fizzy.localhost:3006/cards?collection_ids%5B%5D=#{collections(:writebook).id}"
assert_equal cards_path(indexed_by: "newest", collection_ids: [ collections(:writebook).id ], card_ids: @card_ids), result.url
end
end
+3
View File
@@ -31,6 +31,9 @@ class FilterTest < ActiveSupport::TestCase
filter = users(:david).filters.new indexed_by: "closed"
assert_equal [ cards(:shipping) ], filter.cards
filter = users(:david).filters.new card_ids: [ cards(:logo, :layout).collect(&:id) ]
assert_equal [ cards(:logo), cards(:layout) ], filter.cards
end
test "can't see cards in collections that aren't accessible" do