Commit de68b422 authored by Markus Koller's avatar Markus Koller

Use correct order when repositioning existing designs

Unpositioned designs are sorted by ID, so we need to explictly specify
that order when calling `move_nulls_to_end`.

We also always need to reload the design objects in case their position
was changed in the DB by the `move_nulls_to_end` call.
parent f2202de3
...@@ -137,9 +137,10 @@ module RelativePositioning ...@@ -137,9 +137,10 @@ module RelativePositioning
# If `true`, then all objects with `null` positions are placed _after_ # If `true`, then all objects with `null` positions are placed _after_
# all siblings with positions. If `false`, all objects with `null` # all siblings with positions. If `false`, all objects with `null`
# positions are placed _before_ all siblings with positions. # positions are placed _before_ all siblings with positions.
# @returns [Number] The number of moved records.
def move_nulls(objects, at_end:) def move_nulls(objects, at_end:)
objects = objects.reject(&:relative_position) objects = objects.reject(&:relative_position)
return if objects.empty? return 0 if objects.empty?
representative = objects.first representative = objects.first
number_of_gaps = objects.size + 1 # 1 at left, one between each, and one at right number_of_gaps = objects.size + 1 # 1 at left, one between each, and one at right
...@@ -186,6 +187,8 @@ module RelativePositioning ...@@ -186,6 +187,8 @@ module RelativePositioning
end end
end end
end end
objects.size
end end
end end
......
...@@ -87,10 +87,12 @@ module DesignManagement ...@@ -87,10 +87,12 @@ module DesignManagement
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17788/diffs#note_230875678 # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17788/diffs#note_230875678
order(:relative_position, :id) order(:relative_position, :id)
else else
order(:id) in_creation_order
end end
end end
scope :in_creation_order, -> { reorder(:id) }
scope :with_filename, -> (filenames) { where(filename: filenames) } scope :with_filename, -> (filenames) { where(filename: filenames) }
scope :on_issue, ->(issue) { where(issue_id: issue) } scope :on_issue, ->(issue) { where(issue_id: issue) }
......
...@@ -39,9 +39,12 @@ module DesignManagement ...@@ -39,9 +39,12 @@ module DesignManagement
delegate :issue, :project, to: :current_design delegate :issue, :project, to: :current_design
def move_nulls_to_end def move_nulls_to_end
current_design.class.move_nulls_to_end(issue.designs) moved_records = current_design.class.move_nulls_to_end(issue.designs.in_creation_order)
next_design.reset if next_design && next_design.relative_position.nil? return if moved_records == 0
previous_design.reset if previous_design && previous_design.relative_position.nil?
current_design.reset
next_design&.reset
previous_design&.reset
end end
def neighbors def neighbors
......
---
title: Use correct order when repositioning existing designs
merge_request: 39826
author:
type: fixed
...@@ -185,6 +185,12 @@ RSpec.describe DesignManagement::Design do ...@@ -185,6 +185,12 @@ RSpec.describe DesignManagement::Design do
end end
end end
describe '.in_creation_order' do
it 'sorts by ID in ascending order' do
expect(described_class.in_creation_order).to eq([design1, design2, design3, deleted_design])
end
end
describe '.with_filename' do describe '.with_filename' do
it 'returns correct design when passed a single filename' do it 'returns correct design when passed a single filename' do
expect(described_class.with_filename(design1.filename)).to eq([design1]) expect(described_class.with_filename(design1.filename)).to eq([design1])
......
...@@ -117,9 +117,30 @@ RSpec.describe DesignManagement::MoveDesignsService do ...@@ -117,9 +117,30 @@ RSpec.describe DesignManagement::MoveDesignsService do
let(:previous_design) { designs.second } let(:previous_design) { designs.second }
let(:next_design) { designs.third } let(:next_design) { designs.third }
it 'calls move_between and is successful' do it 'repositions existing designs and correctly places the given design' do
expect(current_design).to receive(:move_between).with(previous_design, next_design) other_design1 = create(:design, issue: issue, relative_position: 10)
other_design2 = create(:design, issue: issue, relative_position: 20)
other_design3, other_design4 = create_list(:design, 2, issue: issue)
expect(subject).to be_success expect(subject).to be_success
expect(issue.designs.ordered(issue.project)).to eq([
# Existing designs which already had a relative_position set.
# These should stay at the beginning, in the same order.
other_design1,
other_design2,
# The designs we're passing into the service.
# These should be placed between the existing designs, in the correct order.
previous_design,
current_design,
next_design,
# Existing designs which didn't have a relative_position set.
# These should be placed at the end, in the order of their IDs.
other_design3,
other_design4
])
end end
end end
end end
......
...@@ -24,7 +24,7 @@ RSpec.shared_examples 'a class that supports relative positioning' do ...@@ -24,7 +24,7 @@ RSpec.shared_examples 'a class that supports relative positioning' do
item3.update!(relative_position: nil) item3.update!(relative_position: nil)
items = [item1, item2, item3] items = [item1, item2, item3]
described_class.move_nulls_to_end(items) expect(described_class.move_nulls_to_end(items)).to be(2)
expect(items.sort_by(&:relative_position)).to eq(items) expect(items.sort_by(&:relative_position)).to eq(items)
expect(item1.relative_position).to be(1000) expect(item1.relative_position).to be(1000)
...@@ -53,9 +53,8 @@ RSpec.shared_examples 'a class that supports relative positioning' do ...@@ -53,9 +53,8 @@ RSpec.shared_examples 'a class that supports relative positioning' do
it 'does not perform any moves if all items have their relative_position set' do it 'does not perform any moves if all items have their relative_position set' do
item1.update!(relative_position: 1) item1.update!(relative_position: 1)
expect do expect(described_class.move_nulls_to_start([item1])).to be(0)
described_class.move_nulls_to_end([item1]) expect(item1.reload.relative_position).to be(1)
end.not_to change { item1.reset.relative_position }
end end
it 'manages to move nulls to the end even if there is a sequence at the end' do it 'manages to move nulls to the end even if there is a sequence at the end' do
...@@ -97,7 +96,7 @@ RSpec.shared_examples 'a class that supports relative positioning' do ...@@ -97,7 +96,7 @@ RSpec.shared_examples 'a class that supports relative positioning' do
item3.update!(relative_position: 1000) item3.update!(relative_position: 1000)
items = [item1, item2, item3] items = [item1, item2, item3]
described_class.move_nulls_to_start(items) expect(described_class.move_nulls_to_start(items)).to be(2)
items.map(&:reload) items.map(&:reload)
expect(items.sort_by(&:relative_position)).to eq(items) expect(items.sort_by(&:relative_position)).to eq(items)
...@@ -128,10 +127,8 @@ RSpec.shared_examples 'a class that supports relative positioning' do ...@@ -128,10 +127,8 @@ RSpec.shared_examples 'a class that supports relative positioning' do
it 'does not perform any moves if all items have their relative_position set' do it 'does not perform any moves if all items have their relative_position set' do
item1.update!(relative_position: 1) item1.update!(relative_position: 1)
described_class.move_nulls_to_start([item1]) expect(described_class.move_nulls_to_start([item1])).to be(0)
item1.reload expect(item1.reload.relative_position).to be(1)
expect(item1.relative_position).to be(1)
end end
end end
......
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