diff options
author | Valery Sizov <valery@gitlab.com> | 2017-03-10 19:04:37 +0200 |
---|---|---|
committer | Valery Sizov <valery@gitlab.com> | 2017-03-14 14:11:59 +0200 |
commit | e752d6d157321f9f10d70cdef1ce1992e263634f (patch) | |
tree | 8e3ba97429243e13b322d81bb60b5b4f3e4b7d9f /app/models/concerns/relative_positioning.rb | |
parent | b84723ac8bf8572c3d261980ab053dda52bc78dd (diff) | |
download | gitlab-ce-e752d6d157321f9f10d70cdef1ce1992e263634f.tar.gz |
[Issue sorting]Addressed review commentsfix_relative_position_calculation
Diffstat (limited to 'app/models/concerns/relative_positioning.rb')
-rw-r--r-- | app/models/concerns/relative_positioning.rb | 77 |
1 files changed, 54 insertions, 23 deletions
diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb index f8ab16a9f4c..f1d8532a6d6 100644 --- a/app/models/concerns/relative_positioning.rb +++ b/app/models/concerns/relative_positioning.rb @@ -4,7 +4,7 @@ module RelativePositioning MIN_POSITION = 0 START_POSITION = Gitlab::Database::MAX_INT_VALUE / 2 MAX_POSITION = Gitlab::Database::MAX_INT_VALUE - DISTANCE = 500 + IDEAL_DISTANCE = 500 included do after_save :save_positionable_neighbours @@ -44,55 +44,86 @@ module RelativePositioning return move_after(before) unless after return move_before(after) unless before + # If there is no place to insert an issue we need to create one by moving the before issue closer + # to its predecessor. This process will recursively move all the predecessors until we have a place + if (after.relative_position - before.relative_position) < 2 + before.move_before + @positionable_neighbours = [before] + end + + self.relative_position = position_between(before.relative_position, after.relative_position) + end + + def move_after(before = self) pos_before = before.relative_position - pos_after = after.relative_position + pos_after = before.next_relative_position - # We can't insert an issue between two other if the distance is 1 or 0 - # so we need to handle this collision properly - if pos_after && (pos_after - pos_before).abs <= 1 - self.relative_position = pos_before - before.move_before(self) - after.move_after(self) + if before.shift_after? + issue_to_move = self.class.in_projects(project.id).find_by!(relative_position: pos_after) + issue_to_move.move_after + @positionable_neighbours = [issue_to_move] - @positionable_neighbours = [before, after] - else - self.relative_position = position_between(pos_before, pos_after) + pos_after = issue_to_move.relative_position end - end - def move_before(after) - self.relative_position = position_between(after.prev_relative_position, after.relative_position) + self.relative_position = position_between(pos_before, pos_after) end - def move_after(before) - self.relative_position = position_between(before.relative_position, before.next_relative_position) + def move_before(after = self) + pos_after = after.relative_position + pos_before = after.prev_relative_position + + if after.shift_before? + issue_to_move = self.class.in_projects(project.id).find_by!(relative_position: pos_before) + issue_to_move.move_before + @positionable_neighbours = [issue_to_move] + + pos_before = issue_to_move.relative_position + end + + self.relative_position = position_between(pos_before, pos_after) end def move_to_end self.relative_position = position_between(max_relative_position || START_POSITION, MAX_POSITION) end + # Indicates if there is an issue that should be shifted to free the place + def shift_after? + next_pos = next_relative_position + next_pos && (next_pos - relative_position) == 1 + end + + # Indicates if there is an issue that should be shifted to free the place + def shift_before? + prev_pos = prev_relative_position + prev_pos && (relative_position - prev_pos) == 1 + end + private # This method takes two integer values (positions) and # calculates the position between them. The range is huge as - # the maximum integer value is 2147483647. We are incrementing position by 1000 every time - # when we have enough space. If distance is less then 500 we are calculating an average number + # the maximum integer value is 2147483647. We are incrementing position by IDEAL_DISTANCE * 2 every time + # when we have enough space. If distance is less then IDEAL_DISTANCE we are calculating an average number def position_between(pos_before, pos_after) pos_before ||= MIN_POSITION pos_after ||= MAX_POSITION pos_before, pos_after = [pos_before, pos_after].sort - if pos_after - pos_before < DISTANCE * 2 - (pos_after + pos_before) / 2 + halfway = (pos_after + pos_before) / 2 + distance_to_halfway = pos_after - halfway + + if distance_to_halfway < IDEAL_DISTANCE + halfway else if pos_before == MIN_POSITION - pos_after - DISTANCE + pos_after - IDEAL_DISTANCE elsif pos_after == MAX_POSITION - pos_before + DISTANCE + pos_before + IDEAL_DISTANCE else - (pos_after + pos_before) / 2 + halfway end end end |