Order board lists by list_type, and position
This commit is contained in:
parent
35420cec0b
commit
b07c5f23b8
14 changed files with 111 additions and 101 deletions
|
@ -1,7 +1,7 @@
|
|||
class Board < ActiveRecord::Base
|
||||
belongs_to :project
|
||||
|
||||
has_many :lists, dependent: :destroy
|
||||
has_many :lists, -> { order(:list_type, :position) }, dependent: :destroy
|
||||
|
||||
validates :project, presence: true
|
||||
end
|
||||
|
|
|
@ -2,9 +2,9 @@ class List < ActiveRecord::Base
|
|||
belongs_to :board
|
||||
belongs_to :label
|
||||
|
||||
enum list_type: { label: 0, backlog: 1, done: 2 }
|
||||
enum list_type: { backlog: 0, label: 1, done: 2 }
|
||||
|
||||
validates :board, :list_type, :position, presence: true
|
||||
validates :label, presence: true, if: :label?
|
||||
validates :position, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
||||
validates :board, :list_type, presence: true
|
||||
validates :label, :position, presence: true, if: :label?
|
||||
validates :position, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, if: :label?
|
||||
end
|
||||
|
|
|
@ -15,8 +15,8 @@ module Boards
|
|||
|
||||
def create_board!
|
||||
project.create_board
|
||||
project.board.lists.create(list_type: :backlog, position: 0)
|
||||
project.board.lists.create(list_type: :done, position: 1)
|
||||
project.board.lists.create(list_type: :backlog)
|
||||
project.board.lists.create(list_type: :done)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,10 +19,7 @@ module Boards
|
|||
attr_reader :board, :params
|
||||
|
||||
def find_next_position
|
||||
return 0 unless board.lists.any?
|
||||
|
||||
records = board.lists.where.not(list_type: List.list_types[:done])
|
||||
records.maximum(:position).to_i + 1
|
||||
board.lists.label.maximum(:position).to_i + 1
|
||||
end
|
||||
|
||||
def create_list_at(position)
|
||||
|
@ -30,8 +27,8 @@ module Boards
|
|||
end
|
||||
|
||||
def increment_higher_lists(position)
|
||||
board.lists.where('position >= ?', position)
|
||||
.update_all('position = position + 1')
|
||||
board.lists.label.where('position >= ?', position)
|
||||
.update_all('position = position + 1')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@ module Boards
|
|||
return false unless list.label?
|
||||
|
||||
list.with_lock do
|
||||
reorder_higher_lists
|
||||
decrement_higher_lists
|
||||
remove_list
|
||||
end
|
||||
end
|
||||
|
@ -23,9 +23,9 @@ module Boards
|
|||
@list ||= board.lists.find(params[:list_id])
|
||||
end
|
||||
|
||||
def reorder_higher_lists
|
||||
board.lists.where('position > ?', list.position)
|
||||
.update_all('position = position - 1')
|
||||
def decrement_higher_lists
|
||||
board.lists.label.where('position > ?', list.position)
|
||||
.update_all('position = position - 1')
|
||||
end
|
||||
|
||||
def remove_list
|
||||
|
|
|
@ -8,7 +8,7 @@ module Boards
|
|||
|
||||
def execute
|
||||
return false unless list.label?
|
||||
return false if invalid_position?
|
||||
return false unless valid_move?
|
||||
|
||||
list.with_lock do
|
||||
reorder_intermediate_lists
|
||||
|
@ -24,18 +24,9 @@ module Boards
|
|||
@list ||= board.lists.find(params[:list_id])
|
||||
end
|
||||
|
||||
def invalid_position?
|
||||
return true if new_position.blank?
|
||||
|
||||
[old_position, first_position, last_position].include?(new_position)
|
||||
end
|
||||
|
||||
def first_position
|
||||
board.lists.first.try(:position)
|
||||
end
|
||||
|
||||
def last_position
|
||||
board.lists.last.try(:position)
|
||||
def valid_move?
|
||||
new_position.present? && new_position != old_position &&
|
||||
new_position >= 0 && new_position <= board.lists.label.size
|
||||
end
|
||||
|
||||
def old_position
|
||||
|
@ -55,15 +46,15 @@ module Boards
|
|||
end
|
||||
|
||||
def decrement_intermediate_lists
|
||||
board.lists.where('position > ?', old_position)
|
||||
.where('position <= ?', new_position)
|
||||
.update_all('position = position - 1')
|
||||
board.lists.label.where('position > ?', old_position)
|
||||
.where('position <= ?', new_position)
|
||||
.update_all('position = position - 1')
|
||||
end
|
||||
|
||||
def increment_intermediate_lists
|
||||
board.lists.where('position >= ?', new_position)
|
||||
.where('position < ?', old_position)
|
||||
.update_all('position = position + 1')
|
||||
board.lists.label.where('position >= ?', new_position)
|
||||
.where('position < ?', old_position)
|
||||
.update_all('position = position + 1')
|
||||
end
|
||||
|
||||
def update_list_position
|
||||
|
|
|
@ -7,8 +7,8 @@ class CreateLists < ActiveRecord::Migration
|
|||
create_table :lists do |t|
|
||||
t.references :board, index: true, foreign_key: true, null: false
|
||||
t.references :label, index: true, foreign_key: true
|
||||
t.integer :list_type, null: false, default: 0
|
||||
t.integer :position, null: false
|
||||
t.integer :list_type, null: false, default: 1
|
||||
t.integer :position
|
||||
|
||||
t.timestamps null: false
|
||||
end
|
||||
|
|
|
@ -544,8 +544,8 @@ ActiveRecord::Schema.define(version: 20160810142633) do
|
|||
create_table "lists", force: :cascade do |t|
|
||||
t.integer "board_id", null: false
|
||||
t.integer "label_id"
|
||||
t.integer "list_type", default: 0, null: false
|
||||
t.integer "position", null: false
|
||||
t.integer "list_type", default: 1, null: false
|
||||
t.integer "position"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
|
|
@ -2,18 +2,22 @@ FactoryGirl.define do
|
|||
factory :list do
|
||||
board
|
||||
label
|
||||
sequence(:position)
|
||||
end
|
||||
|
||||
factory :backlog_list, parent: :list do
|
||||
list_type :backlog
|
||||
label nil
|
||||
position nil
|
||||
end
|
||||
|
||||
factory :label_list, parent: :list do
|
||||
list_type :label
|
||||
sequence(:position)
|
||||
end
|
||||
|
||||
factory :done_list, parent: :list do
|
||||
list_type :done
|
||||
label nil
|
||||
position nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
describe Board do
|
||||
describe 'relationships' do
|
||||
it { is_expected.to belong_to(:project) }
|
||||
it { is_expected.to have_many(:lists).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:lists).order(list_type: :asc, position: :asc).dependent(:destroy) }
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
|
|
|
@ -13,16 +13,18 @@ describe List do
|
|||
it { is_expected.to validate_presence_of(:position) }
|
||||
it { is_expected.to validate_numericality_of(:position).only_integer.is_greater_than_or_equal_to(0) }
|
||||
|
||||
it 'does not require label to be set when list_type is set to backlog' do
|
||||
subject.list_type = :backlog
|
||||
context 'when list_type is set to backlog' do
|
||||
subject { described_class.new(list_type: :backlog) }
|
||||
|
||||
expect(subject).not_to validate_presence_of(:label)
|
||||
it { is_expected.not_to validate_presence_of(:label) }
|
||||
it { is_expected.not_to validate_presence_of(:position) }
|
||||
end
|
||||
|
||||
it 'does not require label to be set when list_type is set to done' do
|
||||
subject.list_type = :done
|
||||
context 'when list_type is set to done' do
|
||||
subject { described_class.new(list_type: :done) }
|
||||
|
||||
expect(subject).not_to validate_presence_of(:label)
|
||||
it { is_expected.not_to validate_presence_of(:label) }
|
||||
it { is_expected.not_to validate_presence_of(:position) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,16 +9,16 @@ describe Boards::Lists::CreateService, services: true do
|
|||
subject(:service) { described_class.new(project, label_id: label.id) }
|
||||
|
||||
context 'when board lists is empty' do
|
||||
it 'creates a new list at begginning of the list' do
|
||||
it 'creates a new list at beginning of the list' do
|
||||
list = service.execute
|
||||
|
||||
expect(list.position).to eq 0
|
||||
expect(list.position).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
context 'when board lists has a backlog list' do
|
||||
it 'creates a new list at end of the list' do
|
||||
create(:backlog_list, board: board, position: 0)
|
||||
context 'when board lists has only a backlog list' do
|
||||
it 'creates a new list at beginning of the list' do
|
||||
create(:backlog_list, board: board)
|
||||
|
||||
list = service.execute
|
||||
|
||||
|
@ -26,9 +26,10 @@ describe Boards::Lists::CreateService, services: true do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when board lists are only labels lists' do
|
||||
it 'creates a new list at end of the list' do
|
||||
create_list(:label_list, 2, board: board)
|
||||
context 'when board lists has only labels lists' do
|
||||
it 'creates a new list at end of the lists' do
|
||||
create(:label_list, board: board, position: 1)
|
||||
create(:label_list, board: board, position: 2)
|
||||
|
||||
list = described_class.new(project, label_id: label.id).execute
|
||||
|
||||
|
@ -36,18 +37,16 @@ describe Boards::Lists::CreateService, services: true do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when board lists has a done list' do
|
||||
it 'creates a new list before' do
|
||||
list1 = create(:backlog_list, board: board, position: 1)
|
||||
list2 = create(:label_list, board: board, position: 2)
|
||||
list3 = create(:done_list, board: board, position: 3)
|
||||
context 'when board lists has backlog, label and done lists' do
|
||||
it 'creates a new list at end of the label lists' do
|
||||
create(:backlog_list, board: board)
|
||||
create(:done_list, board: board)
|
||||
list1 = create(:label_list, board: board, position: 1)
|
||||
|
||||
list = described_class.new(project, label_id: label.id).execute
|
||||
list2 = described_class.new(project, label_id: label.id).execute
|
||||
|
||||
expect(list.position).to eq 3
|
||||
expect(list1.reload.position).to eq 1
|
||||
expect(list2.reload.position).to eq 2
|
||||
expect(list3.reload.position).to eq 4
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,18 +14,18 @@ describe Boards::Lists::DestroyService, services: true do
|
|||
end
|
||||
|
||||
it 'decrements position of higher lists' do
|
||||
list1 = create(:backlog_list, board: board, position: 1)
|
||||
list2 = create(:label_list, board: board, position: 2)
|
||||
list3 = create(:label_list, board: board, position: 3)
|
||||
list4 = create(:label_list, board: board, position: 4)
|
||||
list5 = create(:done_list, board: board, position: 5)
|
||||
backlog = create(:backlog_list, board: board)
|
||||
development = create(:label_list, board: board, position: 1)
|
||||
review = create(:label_list, board: board, position: 2)
|
||||
staging = create(:label_list, board: board, position: 3)
|
||||
done = create(:done_list, board: board)
|
||||
|
||||
described_class.new(project, list_id: list2.id).execute
|
||||
described_class.new(project, list_id: development.id).execute
|
||||
|
||||
expect(list1.reload.position).to eq 1
|
||||
expect(list3.reload.position).to eq 2
|
||||
expect(list4.reload.position).to eq 3
|
||||
expect(list5.reload.position).to eq 4
|
||||
expect(backlog.reload.position).to be_nil
|
||||
expect(review.reload.position).to eq 1
|
||||
expect(staging.reload.position).to eq 2
|
||||
expect(done.reload.position).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,81 +4,98 @@ describe Boards::Lists::MoveService, services: true do
|
|||
describe '#execute' do
|
||||
let(:project) { create(:project_with_board) }
|
||||
let(:board) { project.board }
|
||||
let!(:list1) { create(:backlog_list, board: board, position: 1) }
|
||||
let!(:list2) { create(:label_list, board: board, position: 2) }
|
||||
let!(:list3) { create(:label_list, board: board, position: 3) }
|
||||
let!(:list4) { create(:label_list, board: board, position: 4) }
|
||||
let!(:list5) { create(:label_list, board: board, position: 5) }
|
||||
let!(:list6) { create(:done_list, board: board, position: 6) }
|
||||
|
||||
let!(:backlog) { create(:backlog_list, board: board) }
|
||||
let!(:planning) { create(:label_list, board: board, position: 1) }
|
||||
let!(:development) { create(:label_list, board: board, position: 2) }
|
||||
let!(:review) { create(:label_list, board: board, position: 3) }
|
||||
let!(:staging) { create(:label_list, board: board, position: 4) }
|
||||
let!(:done) { create(:done_list, board: board) }
|
||||
|
||||
context 'when list type is set to label' do
|
||||
it 'keeps position of lists when new position is nil' do
|
||||
service = described_class.new(project, { list_id: list2.id, position: nil })
|
||||
service = described_class.new(project, { list_id: planning.id, position: nil })
|
||||
|
||||
service.execute
|
||||
|
||||
expect(positions_of_lists).to eq [1, 2, 3, 4, 5, 6]
|
||||
expect(current_list_positions).to eq [1, 2, 3, 4]
|
||||
end
|
||||
|
||||
it 'keeps position of lists when new positon is equal to old position' do
|
||||
service = described_class.new(project, { list_id: list2.id, position: 2 })
|
||||
service = described_class.new(project, { list_id: planning.id, position: 1 })
|
||||
|
||||
service.execute
|
||||
|
||||
expect(positions_of_lists).to eq [1, 2, 3, 4, 5, 6]
|
||||
expect(current_list_positions).to eq [1, 2, 3, 4]
|
||||
end
|
||||
|
||||
it 'keeps position of lists when new positon is equal to first position' do
|
||||
service = described_class.new(project, { list_id: list3.id, position: 1 })
|
||||
it 'keeps position of lists when new positon is negative' do
|
||||
service = described_class.new(project, { list_id: planning.id, position: -1 })
|
||||
|
||||
service.execute
|
||||
|
||||
expect(positions_of_lists).to eq [1, 2, 3, 4, 5, 6]
|
||||
expect(current_list_positions).to eq [1, 2, 3, 4]
|
||||
end
|
||||
|
||||
it 'keeps position of lists when new positon is equal to last position' do
|
||||
service = described_class.new(project, { list_id: list3.id, position: 6 })
|
||||
it 'keeps position of lists when new positon is greater than number of labels lists' do
|
||||
service = described_class.new(project, { list_id: planning.id, position: 6 })
|
||||
|
||||
service.execute
|
||||
|
||||
expect(positions_of_lists).to eq [1, 2, 3, 4, 5, 6]
|
||||
expect(current_list_positions).to eq [1, 2, 3, 4]
|
||||
end
|
||||
|
||||
it 'increments position of intermediate lists when new positon is equal to first position' do
|
||||
service = described_class.new(project, { list_id: staging.id, position: 1 })
|
||||
|
||||
service.execute
|
||||
|
||||
expect(current_list_positions).to eq [2, 3, 4, 1]
|
||||
end
|
||||
|
||||
it 'decrements position of intermediate lists when new positon is equal to last position' do
|
||||
service = described_class.new(project, { list_id: planning.id, position: 4 })
|
||||
|
||||
service.execute
|
||||
|
||||
expect(current_list_positions).to eq [4, 1, 2, 3]
|
||||
end
|
||||
|
||||
it 'decrements position of intermediate lists when new position is greater than old position' do
|
||||
service = described_class.new(project, { list_id: list2.id, position: 5 })
|
||||
service = described_class.new(project, { list_id: planning.id, position: 3 })
|
||||
|
||||
service.execute
|
||||
|
||||
expect(positions_of_lists).to eq [1, 5, 2, 3, 4, 6]
|
||||
expect(current_list_positions).to eq [3, 1, 2, 4]
|
||||
end
|
||||
|
||||
it 'increments position of intermediate lists when when new position is lower than old position' do
|
||||
service = described_class.new(project, { list_id: list5.id, position: 2 })
|
||||
it 'increments position of intermediate lists when new position is lower than old position' do
|
||||
service = described_class.new(project, { list_id: staging.id, position: 2 })
|
||||
|
||||
service.execute
|
||||
|
||||
expect(positions_of_lists).to eq [1, 3, 4, 5, 2, 6]
|
||||
expect(current_list_positions).to eq [1, 3, 4, 2]
|
||||
end
|
||||
end
|
||||
|
||||
it 'keeps position of lists when list type is backlog' do
|
||||
service = described_class.new(project, { list_id: list1.id, position: 2 })
|
||||
service = described_class.new(project, { list_id: backlog.id, position: 2 })
|
||||
|
||||
service.execute
|
||||
|
||||
expect(positions_of_lists).to eq [1, 2, 3, 4, 5, 6]
|
||||
expect(current_list_positions).to eq [1, 2, 3, 4]
|
||||
end
|
||||
|
||||
it 'keeps position of lists when list type is done' do
|
||||
service = described_class.new(project, { list_id: list6.id, position: 2 })
|
||||
service = described_class.new(project, { list_id: done.id, position: 2 })
|
||||
|
||||
service.execute
|
||||
|
||||
expect(positions_of_lists).to eq [1, 2, 3, 4, 5, 6]
|
||||
expect(current_list_positions).to eq [1, 2, 3, 4]
|
||||
end
|
||||
end
|
||||
|
||||
def positions_of_lists
|
||||
(1..6).map { |index| send("list#{index}").reload.position }
|
||||
def current_list_positions
|
||||
[planning, development, review, staging].map { |list| list.reload.position }
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue