Commit a7505384 authored by Bob Van Landuyt's avatar Bob Van Landuyt

Merge branch 'eboard-repos-fix' into 'master'

Fix filling of missing position for closed lists

See merge request gitlab-org/gitlab!63852
parents 3ca021ae 5f630a6e
...@@ -6,9 +6,9 @@ module Boards ...@@ -6,9 +6,9 @@ module Boards
include ActiveRecord::ConnectionAdapters::Quoting include ActiveRecord::ConnectionAdapters::Quoting
def execute def execute
return items.order_closed_date_desc if list&.closed? items = init_collection
ordered_items order(items)
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
...@@ -17,7 +17,7 @@ module Boards ...@@ -17,7 +17,7 @@ module Boards
keys = metadata_fields.keys keys = metadata_fields.keys
# TODO: eliminate need for SQL literal fragment # TODO: eliminate need for SQL literal fragment
columns = Arel.sql(metadata_fields.values_at(*keys).join(', ')) columns = Arel.sql(metadata_fields.values_at(*keys).join(', '))
results = item_model.where(id: items.select(issuables[:id])).pluck(columns) results = item_model.where(id: init_collection.select(issuables[:id])).pluck(columns)
Hash[keys.zip(results.flatten)] Hash[keys.zip(results.flatten)]
end end
...@@ -29,7 +29,7 @@ module Boards ...@@ -29,7 +29,7 @@ module Boards
{ size: 'COUNT(*)' } { size: 'COUNT(*)' }
end end
def ordered_items def order(items)
raise NotImplementedError raise NotImplementedError
end end
...@@ -47,8 +47,8 @@ module Boards ...@@ -47,8 +47,8 @@ module Boards
# We memoize the query here since the finder methods we use are quite complex. This does not memoize the result of the query. # We memoize the query here since the finder methods we use are quite complex. This does not memoize the result of the query.
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def items def init_collection
strong_memoize(:items) do strong_memoize(:init_collection) do
filter(finder.execute).reorder(nil) filter(finder.execute).reorder(nil)
end end
end end
......
...@@ -11,7 +11,9 @@ module Boards ...@@ -11,7 +11,9 @@ module Boards
private private
def ordered_items def order(items)
return items.order_closed_date_desc if list&.closed?
items.order_by_position_and_priority(with_cte: params[:search].present?) items.order_by_position_and_priority(with_cte: params[:search].present?)
end end
......
...@@ -129,8 +129,7 @@ module EE ...@@ -129,8 +129,7 @@ module EE
end end
scope :order_relative_position_on_board, ->(board_id) do scope :order_relative_position_on_board, ->(board_id) do
join_board_position(board_id) reorder(::Gitlab::Database.nulls_last_order('boards_epic_board_positions.relative_position', 'ASC'), 'epics.id DESC')
.reorder(::Gitlab::Database.nulls_last_order('boards_epic_board_positions.relative_position', 'ASC'), 'epics.id DESC')
end end
scope :without_board_position, ->(board_id) do scope :without_board_position, ->(board_id) do
......
...@@ -9,20 +9,47 @@ module Boards ...@@ -9,20 +9,47 @@ module Boards
EpicsFinder.new(current_user, filter_params.merge(group_id: parent.id)) EpicsFinder.new(current_user, filter_params.merge(group_id: parent.id))
end end
def filter(items) def filter(collection)
return super unless params[:from_id].present? items = filter_by_from_id(collection)
items = filter_by_position_presence(items)
super.from_id(params[:from_id]) super(items)
end
def filter_by_from_id(items)
return items unless params[:from_id].present?
items.from_id(params[:from_id])
end
def filter_by_position_presence(items)
return items unless exclude_positioned?
items.join_board_position(board.id).without_board_position(board.id)
end
def exclude_positioned?
params[:exclude_positioned].present?
end end
def board def board
@board ||= parent.epic_boards.find(params[:board_id]) @board ||= parent.epic_boards.find(params[:board_id])
end end
def ordered_items def order(items)
items = items.join_board_position(board.id) if needs_board_position?
return items.order_closed_date_desc if list&.closed?
items.order_relative_position_on_board(board.id) items.order_relative_position_on_board(board.id)
end end
def needs_board_position?
# we need to join board's relative position only for unclosed lists
# or if we are filling missing positions in the list
exclude_positioned? || !list&.closed?
end
def item_model def item_model
::Epic ::Epic
end end
......
...@@ -47,10 +47,9 @@ module Boards ...@@ -47,10 +47,9 @@ module Boards
# before the epic being positioned. Epics w/o position are ordered # before the epic being positioned. Epics w/o position are ordered
# by ID in descending order so we need to set position for epics with # by ID in descending order so we need to set position for epics with
# id >= from_id # id >= from_id
list_params = { board_id: board_id, id: list_id, from_id: params[:from_id] } list_params = { board_id: board_id, id: list_id, from_id: params[:from_id], exclude_positioned: true }
Boards::Epics::ListService.new(parent, current_user, list_params).execute Boards::Epics::ListService.new(parent, current_user, list_params).execute
.without_board_position(board_id)
.select(:id) .select(:id)
.limit(LIMIT) .limit(LIMIT)
end end
......
...@@ -62,7 +62,7 @@ RSpec.describe Epic do ...@@ -62,7 +62,7 @@ RSpec.describe Epic do
describe '.order_relative_position_on_board' do describe '.order_relative_position_on_board' do
it 'returns epics ordered by position on the board, null last' do it 'returns epics ordered by position on the board, null last' do
epics = described_class.order_relative_position_on_board(board.id) epics = described_class.join_board_position(board.id).order_relative_position_on_board(board.id)
expect(epics).to eq([epic2, epic3, epic1, public_epic, confidential_epic]) expect(epics).to eq([epic2, epic3, epic1, public_epic, confidential_epic])
end end
......
...@@ -99,9 +99,9 @@ RSpec.describe Epics::UpdateService do ...@@ -99,9 +99,9 @@ RSpec.describe Epics::UpdateService do
context 'when repositioning an epic on a board' do context 'when repositioning an epic on a board' do
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:epic) { create(:epic, group: group) } let_it_be(:epic) { create(:epic, group: group) }
let_it_be(:epic1) { create(:epic, group: group) } let_it_be_with_reload(:epic1) { create(:epic, group: group) }
let_it_be(:epic2) { create(:epic, group: group) } let_it_be_with_reload(:epic2) { create(:epic, group: group) }
let_it_be(:epic3) { create(:epic, group: group) } let_it_be_with_reload(:epic3) { create(:epic, group: group) }
let_it_be(:board) { create(:epic_board, group: group) } let_it_be(:board) { create(:epic_board, group: group) }
let_it_be(:list) { create(:epic_list, epic_board: board, list_type: :backlog) } let_it_be(:list) { create(:epic_list, epic_board: board, list_type: :backlog) }
...@@ -179,6 +179,18 @@ RSpec.describe Epics::UpdateService do ...@@ -179,6 +179,18 @@ RSpec.describe Epics::UpdateService do
context 'when board position records are missing' do context 'when board position records are missing' do
context 'when the position does not exist for any record' do context 'when the position does not exist for any record' do
it_behaves_like 'board repositioning' it_behaves_like 'board repositioning'
context 'when the list is closed' do
let_it_be(:list) { create(:epic_list, epic_board: board, list_type: :closed) }
before do
epic1.update!(state: :closed)
epic2.update!(state: :closed)
epic3.update!(state: :closed)
end
it_behaves_like 'board repositioning'
end
end end
context 'when the epic is in a subgroup' do context 'when the epic is in a subgroup' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment