Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
941aa68
Add move to list option in card
nicolachr Apr 30, 2026
abf51e4
Add specs
nicolachr Apr 30, 2026
d67902a
Add CHANGELOG entry
nicolachr Apr 30, 2026
7b8fab7
Move inline with other actions
nicolachr May 7, 2026
e682e68
Merge branch 'develop' into cards/add-list-dropdown
nicolachr May 7, 2026
4b709e4
Address APR findings
nicolachr May 7, 2026
746bb51
track card list moves in the activity feed
nicolachr May 12, 2026
c9e6ed0
move list filtering out of the card actions partial
nicolachr May 12, 2026
92acb8e
Merge branch 'develop' into cards/add-list-dropdown
nicolachr May 28, 2026
14aebeb
Merge branch 'develop' into cards/add-list-dropdown
nicolachr May 28, 2026
fa11864
Show all lists in dropdown, disable card's current list
nicolachr Jun 4, 2026
8c59b71
Scope card show cache key to card's list
nicolachr Jun 4, 2026
b4264cb
Track move_to_list as an update activity
nicolachr Jun 4, 2026
87511f2
Merge branch 'develop' into cards/add-list-dropdown
nicolachr Jun 4, 2026
1b2ed24
Merge branch 'develop' into cards/add-list-dropdown
nicolachr Jun 18, 2026
12944aa
Extract card move actions into sub-resource controllers
nicolachr Jun 18, 2026
ef8960f
Fix cache invalidation and atomic save in card position/transfer
nicolachr Jun 18, 2026
17cc212
Remove unused Eventable from Card model
nicolachr Jun 19, 2026
eb91548
Merge branch 'develop' into cards/add-list-dropdown
nicolachr Jul 10, 2026
458f24e
Remove transfer controller
aapomm Jul 15, 2026
651c2c9
Update the positions controller to use EventPublisher
aapomm Jul 15, 2026
0c1187a
Merge branch 'develop' into cards/add-list-dropdown
aapomm Jul 15, 2026
77992f9
Merge branch 'develop' into cards/add-list-dropdown
aapomm Aug 3, 2026
42135fd
Add PositionsController for Lists and rename concern
aapomm Aug 3, 2026
f782d5b
Simplify cache key and use link_to_if
aapomm Aug 3, 2026
73e3e33
Add back payload data and use :update for positions controller
aapomm Aug 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[v#.#.#] ([month] [YYYY])
- [entity]:
- [future tense verb] [feature]
- Cards: add option to move a task to a different list
- Mail: add support for SMTP configuration via environment variables for Docker deployments; smtp.yml remains supported for VM deployments during the deprecation transition
- Upgraded gems:
- [gem]
Expand Down
19 changes: 19 additions & 0 deletions app/controllers/cards_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,25 @@ def update
end
end

def move_to_list
Comment thread
nicolachr marked this conversation as resolved.
Outdated
target_list = @board.lists.find(params[:new_list_id])

Card.transaction do
# Repair the source list chain before changing list_id,
# since next_card scopes to self.list
if (next_card = @card.next_card)
next_card.update_attribute(:previous_id, @card.previous_id)
end

@card.list_id = target_list.id
@card.previous_id = target_list.last_card&.id
@card.save
end

track_updated(@card)
redirect_to [current_project, @board, target_list, @card], notice: 'Task moved.'
end

def move
List.move(@card, prev_item: @prev_item, next_item: @next_item)

Expand Down
14 changes: 14 additions & 0 deletions app/views/cards/_actions.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@
<%= link_to(project_board_list_card_revisions_path(current_project, @board, @list, @card), class: 'dropdown-item') do %>
<i class="fa-solid fa-history fa-fw"></i> View History
<% end %>
<% other_lists = @board.ordered_lists.reject { |l| l.id == @list.id } %>
<% if other_lists.any? %>
<div class="dropdown-divider"></div>
<span class="dropdown-item dots-dropdown-header" tabindex="-1">Move to list</span>
<% other_lists.each do |list| %>
<%= link_to(
move_to_list_project_board_list_card_path(current_project, @board, @list, @card, new_list_id: list.id),
method: :post,
class: 'dropdown-item'
) do %>
<%= list.name %>
<% end %>
<% end %>
<% end %>
</div>
</div>
</div>
2 changes: 1 addition & 1 deletion app/views/cards/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<div class="content-container">
<div class="tab-content">
<div class="tab-pane active" id="info-tab">
<% cache ['card-information-tab', @card] do %>
<% cache ['card-information-tab', @card, @board.lists.maximum(:updated_at)] do %>
Comment thread
nicolachr marked this conversation as resolved.
Outdated
<div class="note-text-inner">
<h4 class="mb-4 header-underline">
<span class="text-truncate" title="<%= @card.name %>"><%= @card.name %></span>
Expand Down
5 changes: 4 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@
resources :lists, except: [:index] do
member { post :move }
resources :cards, except: [:index] do
member { post :move }
member do
post :move
post :move_to_list
end
resources :revisions, only: [:index, :show]
end
end
Expand Down
69 changes: 69 additions & 0 deletions spec/requests/cards/move_to_list_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
require 'rails_helper'

describe 'cards#move_to_list' do
before { login_to_project_as_user }

let(:board) { create(:board, node: current_project.methodology_library, project: current_project) }
let(:source_list) { create(:list, board: board) }
let(:target_list) { create(:list, board: board, previous_id: source_list.id) }

let(:card_a) { create(:card, list: source_list) }
let(:card_b) { create(:card, list: source_list, previous_id: card_a.id) }
let(:card_c) { create(:card, list: source_list, previous_id: card_b.id) }

let(:last_card_in_target) { create(:card, list: target_list) }

let(:submit) do
post move_to_list_project_board_list_card_path(current_project, board, source_list, card_b),
params: { new_list_id: target_list.id }
end

before do
card_a
card_b
card_c
last_card_in_target
end

it 'moves the card to the target list' do
submit
expect(card_b.reload.list).to eq(target_list)
end

it 'appends the card to the end of the target list' do
submit
expect(card_b.reload.previous_id).to eq(last_card_in_target.id)
end

it 'repairs the source list chain' do
submit
expect(card_c.reload.previous_id).to eq(card_a.id)
end

it 'redirects to the card in its new list with a notice' do
submit
expect(response).to redirect_to(project_board_list_card_path(current_project, board, target_list, card_b))
expect(flash[:notice]).to eq('Task moved.')
end

it 'creates an activity' do
expect { submit }.to have_enqueued_job(ActivityTrackingJob).with(
action: 'update',
project_id: current_project.id,
trackable_id: card_b.id,
trackable_type: 'Card',
user_id: @logged_in_as.id
)
end

context 'when the target list is empty' do
let(:last_card_in_target) { nil }

before { target_list }

it 'makes the card the first item in the target list' do
submit
expect(card_b.reload.previous_id).to be_nil
end
end
end
Loading