Commit c6701d45 authored by Sean McGivern's avatar Sean McGivern

Merge branch 'issue_20900' into 'master'

Remove issuable drag and drop and sorting from milestone view

Closes #20900

See merge request !11950
parents 451cbe1f 0520ee44
...@@ -4,87 +4,7 @@ ...@@ -4,87 +4,7 @@
(function() { (function() {
this.Milestone = (function() { this.Milestone = (function() {
Milestone.updateIssue = function(li, issue_url, data) {
return $.ajax({
type: "PUT",
url: issue_url,
data: data,
success: function(_data) {
return Milestone.successCallback(_data, li);
},
error: function(data) {
return new Flash("Issue update failed", 'alert');
},
dataType: "json"
});
};
Milestone.sortIssues = function(url, data) {
return $.ajax({
type: "PUT",
url,
data: data,
success: function(_data) {
return Milestone.successCallback(_data);
},
error: function() {
return new Flash("Issues update failed", 'alert');
},
dataType: "json"
});
};
Milestone.sortMergeRequests = function(url, data) {
return $.ajax({
type: "PUT",
url,
data: data,
success: function(_data) {
return Milestone.successCallback(_data);
},
error: function(data) {
return new Flash("Issue update failed", 'alert');
},
dataType: "json"
});
};
Milestone.updateMergeRequest = function(li, merge_request_url, data) {
return $.ajax({
type: "PUT",
url: merge_request_url,
data: data,
success: function(_data) {
return Milestone.successCallback(_data, li);
},
error: function(data) {
return new Flash("Issue update failed", 'alert');
},
dataType: "json"
});
};
Milestone.successCallback = function(data, element) {
const $avatarContainer = $(element).find('.assignee-icon');
$avatarContainer.empty();
if (data.assignees && data.assignees.length > 0) {
const $avatars = data.assignees.map((assignee) => {
const img_tag = $('<img/>');
img_tag.attr('src', assignee.avatar_url);
img_tag.addClass('avatar s16');
return img_tag;
});
$avatarContainer.append($avatars);
}
};
function Milestone() { function Milestone() {
this.issuesSortEndpoint = $('#tab-issues').data('sort-endpoint');
this.mergeRequestsSortEndpoint = $('#tab-merge-requests').data('sort-endpoint');
this.bindIssuesSorting();
this.bindTabsSwitching(); this.bindTabsSwitching();
// Load merge request tab if it is active // Load merge request tab if it is active
...@@ -94,22 +14,6 @@ ...@@ -94,22 +14,6 @@
this.loadInitialTab(); this.loadInitialTab();
} }
Milestone.prototype.bindIssuesSorting = function() {
if (!this.issuesSortEndpoint) return;
$('#issues-list-unassigned, #issues-list-ongoing, #issues-list-closed').each(function (i, el) {
this.createSortable(el, {
group: 'issue-list',
listEls: $('.issues-sortable-list'),
fieldName: 'issue',
sortCallback: (data) => {
Milestone.sortIssues(this.issuesSortEndpoint, data);
},
updateCallback: Milestone.updateIssue,
});
}.bind(this));
};
Milestone.prototype.bindTabsSwitching = function() { Milestone.prototype.bindTabsSwitching = function() {
return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => { return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => {
const $target = $(e.target); const $target = $(e.target);
...@@ -119,69 +23,6 @@ ...@@ -119,69 +23,6 @@
}); });
}; };
Milestone.prototype.bindMergeRequestSorting = function() {
if (!this.mergeRequestsSortEndpoint) return;
$("#merge_requests-list-unassigned, #merge_requests-list-ongoing, #merge_requests-list-closed").each(function (i, el) {
this.createSortable(el, {
group: 'merge-request-list',
listEls: $(".merge_requests-sortable-list:not(#merge_requests-list-merged)"),
fieldName: 'merge_request',
sortCallback: (data) => {
Milestone.sortMergeRequests(this.mergeRequestsSortEndpoint, data);
},
updateCallback: Milestone.updateMergeRequest,
});
}.bind(this));
};
Milestone.prototype.createSortable = function(el, opts) {
return Sortable.create(el, {
group: opts.group,
filter: '.is-disabled',
forceFallback: true,
onStart: function(e) {
opts.listEls.css('min-height', e.item.offsetHeight);
},
onEnd: function () {
opts.listEls.css("min-height", "0px");
},
onUpdate: function(e) {
var ids = this.toArray(),
data;
if (ids.length) {
data = ids.map(function(id) {
return 'sortable_' + opts.fieldName + '[]=' + id;
}).join('&');
opts.sortCallback(data);
}
},
onAdd: function (e) {
var data, issuableId, issuableUrl, newState;
newState = e.to.dataset.state;
issuableUrl = e.item.dataset.url;
data = (function() {
switch (newState) {
case 'ongoing':
return `${opts.fieldName}[assignee_ids][]=${gon.current_user_id}`;
case 'unassigned':
return `${opts.fieldName}[assignee_ids][]=0`;
case 'closed':
return opts.fieldName + '[state_event]=close';
}
})();
if (e.from.dataset.state === 'closed') {
data += '&' + opts.fieldName + '[state_event]=reopen';
}
opts.updateCallback(e.item, issuableUrl, data);
this.options.onUpdate.call(this, e);
}
});
};
Milestone.prototype.loadInitialTab = function() { Milestone.prototype.loadInitialTab = function() {
const $target = $(`.js-milestone-tabs a[href="${location.hash}"]`); const $target = $(`.js-milestone-tabs a[href="${location.hash}"]`);
...@@ -203,10 +44,6 @@ ...@@ -203,10 +44,6 @@
.done((data) => { .done((data) => {
$(tabElId).html(data.html); $(tabElId).html(data.html);
$target.addClass('is-loaded'); $target.addClass('is-loaded');
if (tabElId === '#tab-merge-requests') {
this.bindMergeRequestSorting();
}
}); });
} }
}; };
......
...@@ -111,8 +111,8 @@ ...@@ -111,8 +111,8 @@
} }
} }
.issues-sortable-list, .milestone-issues-list,
.merge_requests-sortable-list { .milestone-merge_requests-list {
.issuable-detail { .issuable-detail {
display: block; display: block;
margin-top: 7px; margin-top: 7px;
...@@ -197,6 +197,4 @@ ...@@ -197,6 +197,4 @@
.issuable-row { .issuable-row {
background-color: $white-light; background-color: $white-light;
cursor: -webkit-grab;
cursor: grab;
} }
...@@ -6,7 +6,7 @@ module MilestoneActions ...@@ -6,7 +6,7 @@ module MilestoneActions
format.html { redirect_to milestone_redirect_path } format.html { redirect_to milestone_redirect_path }
format.json do format.json do
render json: tabs_json("shared/milestones/_merge_requests_tab", { render json: tabs_json("shared/milestones/_merge_requests_tab", {
merge_requests: @milestone.merge_requests, merge_requests: @milestone.sorted_merge_requests,
show_project_name: true show_project_name: true
}) })
end end
......
...@@ -2,7 +2,7 @@ class Projects::MilestonesController < Projects::ApplicationController ...@@ -2,7 +2,7 @@ class Projects::MilestonesController < Projects::ApplicationController
include MilestoneActions include MilestoneActions
before_action :module_enabled before_action :module_enabled
before_action :milestone, only: [:edit, :update, :destroy, :show, :sort_issues, :sort_merge_requests, :merge_requests, :participants, :labels] before_action :milestone, only: [:edit, :update, :destroy, :show, :merge_requests, :participants, :labels]
# Allow read any milestone # Allow read any milestone
before_action :authorize_read_milestone! before_action :authorize_read_milestone!
...@@ -85,22 +85,6 @@ class Projects::MilestonesController < Projects::ApplicationController ...@@ -85,22 +85,6 @@ class Projects::MilestonesController < Projects::ApplicationController
end end
end end
def sort_issues
@milestone.sort_issues(params['sortable_issue'].map(&:to_i))
render json: { saved: true }
end
def sort_merge_requests
@merge_requests = @milestone.merge_requests.where(id: params['sortable_merge_request'])
@merge_requests.each do |merge_request|
merge_request.position = params['sortable_merge_request'].index(merge_request.id.to_s) + 1
merge_request.save
end
render json: { saved: true }
end
protected protected
def milestone def milestone
......
...@@ -67,7 +67,6 @@ module Issuable ...@@ -67,7 +67,6 @@ module Issuable
scope :authored, ->(user) { where(author_id: user) } scope :authored, ->(user) { where(author_id: user) }
scope :recent, -> { reorder(id: :desc) } scope :recent, -> { reorder(id: :desc) }
scope :order_position_asc, -> { reorder(position: :asc) }
scope :of_projects, ->(ids) { where(project_id: ids) } scope :of_projects, ->(ids) { where(project_id: ids) }
scope :of_milestones, ->(ids) { where(milestone_id: ids) } scope :of_milestones, ->(ids) { where(milestone_id: ids) }
scope :with_milestone, ->(title) { left_joins_milestones.where(milestones: { title: title }) } scope :with_milestone, ->(title) { left_joins_milestones.where(milestones: { title: title }) }
...@@ -139,7 +138,6 @@ module Issuable ...@@ -139,7 +138,6 @@ module Issuable
when 'upvotes_desc' then order_upvotes_desc when 'upvotes_desc' then order_upvotes_desc
when 'label_priority' then order_labels_priority(excluded_labels: excluded_labels) when 'label_priority' then order_labels_priority(excluded_labels: excluded_labels)
when 'priority' then order_due_date_and_labels_priority(excluded_labels: excluded_labels) when 'priority' then order_due_date_and_labels_priority(excluded_labels: excluded_labels)
when 'position_asc' then order_position_asc
else else
order_by(method) order_by(method)
end end
......
...@@ -40,10 +40,18 @@ module Milestoneish ...@@ -40,10 +40,18 @@ module Milestoneish
def issues_visible_to_user(user) def issues_visible_to_user(user)
memoize_per_user(user, :issues_visible_to_user) do memoize_per_user(user, :issues_visible_to_user) do
IssuesFinder.new(user, issues_finder_params) IssuesFinder.new(user, issues_finder_params)
.execute.includes(:assignees).where(milestone_id: milestoneish_ids) .execute.preload(:assignees).where(milestone_id: milestoneish_ids)
end end
end end
def sorted_issues(user)
issues_visible_to_user(user).preload_associations.sort('label_priority')
end
def sorted_merge_requests
merge_requests.sort('label_priority')
end
def upcoming? def upcoming?
start_date && start_date.future? start_date && start_date.future?
end end
......
...@@ -9,6 +9,9 @@ class Issue < ActiveRecord::Base ...@@ -9,6 +9,9 @@ class Issue < ActiveRecord::Base
include Spammable include Spammable
include FasterCacheKeys include FasterCacheKeys
include RelativePositioning include RelativePositioning
include IgnorableColumn
ignore_column :position
DueDateStruct = Struct.new(:title, :name).freeze DueDateStruct = Struct.new(:title, :name).freeze
NoDueDate = DueDateStruct.new('No Due Date', '0').freeze NoDueDate = DueDateStruct.new('No Due Date', '0').freeze
...@@ -44,7 +47,7 @@ class Issue < ActiveRecord::Base ...@@ -44,7 +47,7 @@ class Issue < ActiveRecord::Base
scope :created_after, -> (datetime) { where("created_at >= ?", datetime) } scope :created_after, -> (datetime) { where("created_at >= ?", datetime) }
scope :include_associations, -> { includes(:labels, project: :namespace) } scope :preload_associations, -> { preload(:labels, project: :namespace) }
after_save :expire_etag_cache after_save :expire_etag_cache
......
...@@ -4,6 +4,9 @@ class MergeRequest < ActiveRecord::Base ...@@ -4,6 +4,9 @@ class MergeRequest < ActiveRecord::Base
include Noteable include Noteable
include Referable include Referable
include Sortable include Sortable
include IgnorableColumn
ignore_column :position
belongs_to :target_project, class_name: "Project" belongs_to :target_project, class_name: "Project"
belongs_to :source_project, class_name: "Project" belongs_to :source_project, class_name: "Project"
......
...@@ -164,38 +164,6 @@ class Milestone < ActiveRecord::Base ...@@ -164,38 +164,6 @@ class Milestone < ActiveRecord::Base
write_attribute(:title, sanitize_title(value)) if value.present? write_attribute(:title, sanitize_title(value)) if value.present?
end end
# Sorts the issues for the given IDs.
#
# This method runs a single SQL query using a CASE statement to update the
# position of all issues in the current milestone (scoped to the list of IDs).
#
# Given the ids [10, 20, 30] this method produces a SQL query something like
# the following:
#
# UPDATE issues
# SET position = CASE
# WHEN id = 10 THEN 1
# WHEN id = 20 THEN 2
# WHEN id = 30 THEN 3
# ELSE position
# END
# WHERE id IN (10, 20, 30);
#
# This method expects that the IDs given in `ids` are already Fixnums.
def sort_issues(ids)
pairs = []
ids.each_with_index do |id, index|
pairs << id
pairs << index + 1
end
conditions = 'WHEN id = ? THEN ? ' * ids.length
issues.where(id: ids).
update_all(["position = CASE #{conditions} ELSE position END", *pairs])
end
private private
def milestone_format_reference(format = :iid) def milestone_format_reference(format = :iid)
......
...@@ -5,7 +5,6 @@ class IssuableEntity < Grape::Entity ...@@ -5,7 +5,6 @@ class IssuableEntity < Grape::Entity
expose :description expose :description
expose :lock_version expose :lock_version
expose :milestone_id expose :milestone_id
expose :position
expose :state expose :state
expose :title expose :title
expose :updated_by_id expose :updated_by_id
......
...@@ -8,11 +8,11 @@ ...@@ -8,11 +8,11 @@
= title = title
- if show_counter - if show_counter
.counter .counter
= number_with_delimiter(issuables.size) = number_with_delimiter(issuables.length)
- class_prefix = dom_class(issuables).pluralize - class_prefix = dom_class(issuables).pluralize
%ul{ class: "well-list #{class_prefix}-sortable-list", id: "#{class_prefix}-list-#{id}", "data-state" => id } %ul{ class: "well-list milestone-#{class_prefix}-list", id: "#{class_prefix}-list-#{id}" }
= render partial: 'shared/milestones/issuable', = render partial: 'shared/milestones/issuable',
collection: issuables.order_position_asc, collection: issuables,
as: :issuable, as: :issuable,
locals: { show_project_name: show_project_name, show_full_project_name: show_full_project_name } locals: { show_project_name: show_project_name, show_full_project_name: show_full_project_name }
...@@ -31,12 +31,12 @@ ...@@ -31,12 +31,12 @@
.tab-content.milestone-content .tab-content.milestone-content
- if milestone.is_a?(GlobalMilestone) || can?(current_user, :read_issue, @project) - if milestone.is_a?(GlobalMilestone) || can?(current_user, :read_issue, @project)
.tab-pane.active#tab-issues{ data: { sort_endpoint: (sort_issues_namespace_project_milestone_path(@project.namespace, @project, @milestone) if @project && current_user) } } .tab-pane.active#tab-issues{ data: { sort_endpoint: (sort_issues_namespace_project_milestone_path(@project.namespace, @project, @milestone) if @project && current_user) } }
= render 'shared/milestones/issues_tab', issues: milestone.issues_visible_to_user(current_user).include_associations, show_project_name: show_project_name, show_full_project_name: show_full_project_name = render 'shared/milestones/issues_tab', issues: milestone.sorted_issues(current_user), show_project_name: show_project_name, show_full_project_name: show_full_project_name
.tab-pane#tab-merge-requests{ data: { sort_endpoint: (sort_merge_requests_namespace_project_milestone_path(@project.namespace, @project, @milestone) if @project && current_user) } } .tab-pane#tab-merge-requests
-# loaded async -# loaded async
= render "shared/milestones/tab_loading" = render "shared/milestones/tab_loading"
- else - else
.tab-pane.active#tab-merge-requests{ data: { sort_endpoint: (sort_merge_requests_namespace_project_milestone_path(@project.namespace, @project, @milestone) if @project && current_user) } } .tab-pane.active#tab-merge-requests
-# loaded async -# loaded async
= render "shared/milestones/tab_loading" = render "shared/milestones/tab_loading"
.tab-pane#tab-participants .tab-pane#tab-participants
......
---
title: Remove issues/merge requests drag n drop and sorting from milestone view
merge_request:
author:
class RemovePositionFromIssuables < ActiveRecord::Migration
DOWNTIME = false
def change
remove_column :issues, :position, :integer
remove_column :merge_requests, :position, :integer
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170607121233) do ActiveRecord::Schema.define(version: 20170609183112) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -547,7 +547,6 @@ ActiveRecord::Schema.define(version: 20170607121233) do ...@@ -547,7 +547,6 @@ ActiveRecord::Schema.define(version: 20170607121233) do
t.integer "project_id" t.integer "project_id"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.integer "position", default: 0
t.string "branch_name" t.string "branch_name"
t.text "description" t.text "description"
t.integer "milestone_id" t.integer "milestone_id"
...@@ -738,7 +737,6 @@ ActiveRecord::Schema.define(version: 20170607121233) do ...@@ -738,7 +737,6 @@ ActiveRecord::Schema.define(version: 20170607121233) do
t.integer "target_project_id", null: false t.integer "target_project_id", null: false
t.integer "iid" t.integer "iid"
t.text "description" t.text "description"
t.integer "position", default: 0
t.datetime "locked_at" t.datetime "locked_at"
t.integer "updated_by_id" t.integer "updated_by_id"
t.text "merge_error" t.text "merge_error"
......
...@@ -117,7 +117,7 @@ module API ...@@ -117,7 +117,7 @@ module API
finder_params = { finder_params = {
project_id: user_project.id, project_id: user_project.id,
milestone_title: milestone.title, milestone_title: milestone.title,
sort: 'position_asc' sort: 'label_priority'
} }
issues = IssuesFinder.new(current_user, finder_params).execute issues = IssuesFinder.new(current_user, finder_params).execute
...@@ -140,7 +140,7 @@ module API ...@@ -140,7 +140,7 @@ module API
finder_params = { finder_params = {
project_id: user_project.id, project_id: user_project.id,
milestone_title: milestone.title, milestone_title: milestone.title,
sort: 'position_asc' sort: 'label_priority'
} }
merge_requests = MergeRequestsFinder.new(current_user, finder_params).execute merge_requests = MergeRequestsFinder.new(current_user, finder_params).execute
......
...@@ -23,7 +23,7 @@ describe 'Dashboard milestone tabs', :js, :feature do ...@@ -23,7 +23,7 @@ describe 'Dashboard milestone tabs', :js, :feature do
it 'loads merge requests async' do it 'loads merge requests async' do
click_link 'Merge Requests' click_link 'Merge Requests'
expect(page).to have_selector('.merge_requests-sortable-list') expect(page).to have_selector('.milestone-merge_requests-list')
end end
it 'loads participants async' do it 'loads participants async' do
......
require 'rails_helper' # require 'rails_helper'
describe 'Milestone draggable', feature: true, js: true do # describe 'Milestone draggable', feature: true, js: true do
include DragTo # include DragTo
let(:milestone) { create(:milestone, project: project, title: 8.14) } # let(:milestone) { create(:milestone, project: project, title: 8.14) }
let(:project) { create(:empty_project, :public) } # let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) } # let(:user) { create(:user) }
context 'issues' do # context 'issues' do
let(:issue) { page.find_by_id('issues-list-unassigned').find('li') } # let(:issue) { page.find_by_id('issues-list-unassigned').find('li') }
let(:issue_target) { page.find_by_id('issues-list-ongoing') } # let(:issue_target) { page.find_by_id('issues-list-ongoing') }
it 'does not allow guest to drag issue' do # it 'does not allow guest to drag issue' do
create_and_drag_issue # create_and_drag_issue
expect(issue_target).not_to have_selector('.issuable-row') # expect(issue_target).not_to have_selector('.issuable-row')
end # end
it 'does not allow authorized user to drag issue' do # it 'does not allow authorized user to drag issue' do
login_as(user) # login_as(user)
create_and_drag_issue # create_and_drag_issue
expect(issue_target).not_to have_selector('.issuable-row') # expect(issue_target).not_to have_selector('.issuable-row')
end # end
it 'allows author to drag issue' do # it 'allows author to drag issue' do
login_as(user) # login_as(user)
create_and_drag_issue(author: user) # create_and_drag_issue(author: user)
expect(issue_target).to have_selector('.issuable-row') # expect(issue_target).to have_selector('.issuable-row')
end # end
it 'allows admin to drag issue' do # it 'allows admin to drag issue' do
login_as(:admin) # login_as(:admin)
create_and_drag_issue
expect(issue_target).to have_selector('.issuable-row') # create_and_drag_issue
end
it 'assigns issue when it has been dragged to ongoing list' do # expect(issue_target).to have_selector('.issuable-row')
login_as(:admin) # end
create_and_drag_issue # end
expect(@issue.reload.assignees).not_to be_empty # context 'merge requests' do
expect(page).to have_selector("#sortable_issue_#{@issue.iid} .assignee-icon img", count: 1) # let(:merge_request) { page.find_by_id('merge_requests-list-unassigned').find('li') }
end # let(:merge_request_target) { page.find_by_id('merge_requests-list-ongoing') }
end
context 'merge requests' do # it 'does not allow guest to drag merge request' do
let(:merge_request) { page.find_by_id('merge_requests-list-unassigned').find('li') } # create_and_drag_merge_request
let(:merge_request_target) { page.find_by_id('merge_requests-list-ongoing') }
it 'does not allow guest to drag merge request' do # expect(merge_request_target).not_to have_selector('.issuable-row')
create_and_drag_merge_request # end
expect(merge_request_target).not_to have_selector('.issuable-row') # it 'does not allow authorized user to drag merge request' do
end # login_as(user)
# create_and_drag_merge_request
it 'does not allow authorized user to drag merge request' do # expect(merge_request_target).not_to have_selector('.issuable-row')
login_as(user) # end
create_and_drag_merge_request
expect(merge_request_target).not_to have_selector('.issuable-row') # it 'allows author to drag merge request' do
end # login_as(user)
# create_and_drag_merge_request(author: user)
it 'allows author to drag merge request' do # expect(merge_request_target).to have_selector('.issuable-row')
login_as(user) # end
create_and_drag_merge_request(author: user)
expect(merge_request_target).to have_selector('.issuable-row') # it 'allows admin to drag merge request' do
end # login_as(:admin)
# create_and_drag_merge_request
it 'allows admin to drag merge request' do # expect(merge_request_target).to have_selector('.issuable-row')
login_as(:admin) # end
create_and_drag_merge_request # end
expect(merge_request_target).to have_selector('.issuable-row') # def create_and_drag_issue(params = {})
end # create(:issue, params.merge(title: 'Foo', project: project, milestone: milestone))
end
def create_and_drag_issue(params = {}) # visit namespace_project_milestone_path(project.namespace, project, milestone)
@issue = create(:issue, params.merge(title: 'Foo', project: project, milestone: milestone)) # scroll_into_view('.milestone-content')
# drag_to(selector: '.issues-sortable-list', list_to_index: 1)
visit namespace_project_milestone_path(project.namespace, project, milestone) # wait_for_requests
scroll_into_view('.milestone-content') # end
drag_to(selector: '.issues-sortable-list', list_to_index: 1)
wait_for_requests # def create_and_drag_merge_request(params = {})
end # create(:merge_request, params.merge(title: 'Foo', source_project: project, target_project: project, milestone: milestone))
def create_and_drag_merge_request(params = {}) # visit namespace_project_milestone_path(project.namespace, project, milestone)
create(:merge_request, params.merge(title: 'Foo', source_project: project, target_project: project, milestone: milestone)) # page.find("a[href='#tab-merge-requests']").click
visit namespace_project_milestone_path(project.namespace, project, milestone) # wait_for_requests
page.find("a[href='#tab-merge-requests']").click
wait_for_requests # scroll_into_view('.milestone-content')
# drag_to(selector: '.merge_requests-sortable-list', list_to_index: 1)
scroll_into_view('.milestone-content') # wait_for_requests
drag_to(selector: '.merge_requests-sortable-list', list_to_index: 1) # end
wait_for_requests # def scroll_into_view(selector)
end # page.evaluate_script("document.querySelector('#{selector}').scrollIntoView();")
# end
def scroll_into_view(selector) # end
page.evaluate_script("document.querySelector('#{selector}').scrollIntoView();")
end
end
...@@ -19,12 +19,43 @@ describe Milestone, 'Milestoneish' do ...@@ -19,12 +19,43 @@ describe Milestone, 'Milestoneish' do
let!(:closed_security_issue_3) { create(:issue, :confidential, :closed, project: project, author: author, milestone: milestone) } let!(:closed_security_issue_3) { create(:issue, :confidential, :closed, project: project, author: author, milestone: milestone) }
let!(:closed_security_issue_4) { create(:issue, :confidential, :closed, project: project, assignees: [assignee], milestone: milestone) } let!(:closed_security_issue_4) { create(:issue, :confidential, :closed, project: project, assignees: [assignee], milestone: milestone) }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) } let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) }
let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) }
let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) }
let(:label_3) { create(:label, title: 'label_3', project: project) }
before do before do
project.team << [member, :developer] project.team << [member, :developer]
project.team << [guest, :guest] project.team << [guest, :guest]
end end
describe '#sorted_issues' do
it 'sorts issues by label priority' do
issue.labels << label_1
security_issue_1.labels << label_2
closed_issue_1.labels << label_3
issues = milestone.sorted_issues(member)
expect(issues.first).to eq(issue)
expect(issues.second).to eq(security_issue_1)
expect(issues.third).not_to eq(closed_issue_1)
end
end
describe '#sorted_merge_requests' do
it 'sorts merge requests by label priority' do
merge_request_1 = create(:labeled_merge_request, labels: [label_2], source_project: project, source_branch: 'branch_1', milestone: milestone)
merge_request_2 = create(:labeled_merge_request, labels: [label_1], source_project: project, source_branch: 'branch_2', milestone: milestone)
merge_request_3 = create(:labeled_merge_request, labels: [label_3], source_project: project, source_branch: 'branch_3', milestone: milestone)
merge_requests = milestone.sorted_merge_requests
expect(merge_requests.first).to eq(merge_request_2)
expect(merge_requests.second).to eq(merge_request_1)
expect(merge_requests.third).to eq(merge_request_3)
end
end
describe '#closed_items_count' do describe '#closed_items_count' do
it 'does not count confidential issues for non project members' do it 'does not count confidential issues for non project members' do
expect(milestone.closed_items_count(non_member)).to eq 2 expect(milestone.closed_items_count(non_member)).to eq 2
......
...@@ -144,35 +144,6 @@ describe Milestone, models: true do ...@@ -144,35 +144,6 @@ describe Milestone, models: true do
end end
end end
describe '#sort_issues' do
let(:milestone) { create(:milestone) }
let(:issue1) { create(:issue, milestone: milestone, position: 1) }
let(:issue2) { create(:issue, milestone: milestone, position: 2) }
let(:issue3) { create(:issue, milestone: milestone, position: 3) }
let(:issue4) { create(:issue, position: 42) }
it 'sorts the given issues' do
milestone.sort_issues([issue3.id, issue2.id, issue1.id])
issue1.reload
issue2.reload
issue3.reload
expect(issue1.position).to eq(3)
expect(issue2.position).to eq(2)
expect(issue3.position).to eq(1)
end
it 'ignores issues not part of the milestone' do
milestone.sort_issues([issue3.id, issue2.id, issue1.id, issue4.id])
issue4.reload
expect(issue4.position).to eq(42)
end
end
describe '.search' do describe '.search' do
let(:milestone) { create(:milestone, title: 'foo', description: 'bar') } let(:milestone) { create(:milestone, title: 'foo', description: 'bar') }
......
...@@ -5,6 +5,9 @@ describe API::Milestones do ...@@ -5,6 +5,9 @@ describe API::Milestones do
let!(:project) { create(:empty_project, namespace: user.namespace ) } let!(:project) { create(:empty_project, namespace: user.namespace ) }
let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') } let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') }
let!(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') } let!(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') }
let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) }
let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) }
let(:label_3) { create(:label, title: 'label_3', project: project) }
before do before do
project.team << [user, :developer] project.team << [user, :developer]
...@@ -228,6 +231,18 @@ describe API::Milestones do ...@@ -228,6 +231,18 @@ describe API::Milestones do
expect(json_response.first['milestone']['title']).to eq(milestone.title) expect(json_response.first['milestone']['title']).to eq(milestone.title)
end end
it 'returns project issues sorted by label priority' do
issue_1 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_3])
issue_2 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_1])
issue_3 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_2])
get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user)
expect(json_response.first['id']).to eq(issue_2.id)
expect(json_response.second['id']).to eq(issue_3.id)
expect(json_response.third['id']).to eq(issue_1.id)
end
it 'matches V4 response schema for a list of issues' do it 'matches V4 response schema for a list of issues' do
get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user) get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user)
...@@ -244,8 +259,8 @@ describe API::Milestones do ...@@ -244,8 +259,8 @@ describe API::Milestones do
describe 'confidential issues' do describe 'confidential issues' do
let(:public_project) { create(:empty_project, :public) } let(:public_project) { create(:empty_project, :public) }
let(:milestone) { create(:milestone, project: public_project) } let(:milestone) { create(:milestone, project: public_project) }
let(:issue) { create(:issue, project: public_project, position: 2) } let(:issue) { create(:issue, project: public_project) }
let(:confidential_issue) { create(:issue, confidential: true, project: public_project, position: 1) } let(:confidential_issue) { create(:issue, confidential: true, project: public_project) }
before do before do
public_project.team << [user, :developer] public_project.team << [user, :developer]
...@@ -285,7 +300,10 @@ describe API::Milestones do ...@@ -285,7 +300,10 @@ describe API::Milestones do
expect(json_response.map { |issue| issue['id'] }).to include(issue.id) expect(json_response.map { |issue| issue['id'] }).to include(issue.id)
end end
it 'returns issues ordered by position asc' do it 'returns issues ordered by label priority' do
issue.labels << label_2
confidential_issue.labels << label_1
get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", user) get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", user)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
...@@ -299,8 +317,8 @@ describe API::Milestones do ...@@ -299,8 +317,8 @@ describe API::Milestones do
end end
describe 'GET /projects/:id/milestones/:milestone_id/merge_requests' do describe 'GET /projects/:id/milestones/:milestone_id/merge_requests' do
let(:merge_request) { create(:merge_request, source_project: project, position: 2) } let(:merge_request) { create(:merge_request, source_project: project) }
let(:another_merge_request) { create(:merge_request, :simple, source_project: project, position: 1) } let(:another_merge_request) { create(:merge_request, :simple, source_project: project) }
before do before do
milestone.merge_requests << merge_request milestone.merge_requests << merge_request
...@@ -318,6 +336,18 @@ describe API::Milestones do ...@@ -318,6 +336,18 @@ describe API::Milestones do
expect(json_response.first['milestone']['title']).to eq(milestone.title) expect(json_response.first['milestone']['title']).to eq(milestone.title)
end end
it 'returns project merge_requests sorted by label priority' do
merge_request_1 = create(:labeled_merge_request, source_branch: 'branch_1', source_project: project, milestone: milestone, labels: [label_2])
merge_request_2 = create(:labeled_merge_request, source_branch: 'branch_2', source_project: project, milestone: milestone, labels: [label_1])
merge_request_3 = create(:labeled_merge_request, source_branch: 'branch_3', source_project: project, milestone: milestone, labels: [label_3])
get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user)
expect(json_response.first['id']).to eq(merge_request_2.id)
expect(json_response.second['id']).to eq(merge_request_1.id)
expect(json_response.third['id']).to eq(merge_request_3.id)
end
it 'returns a 404 error if milestone id not found' do it 'returns a 404 error if milestone id not found' do
get api("/projects/#{project.id}/milestones/1234/merge_requests", user) get api("/projects/#{project.id}/milestones/1234/merge_requests", user)
...@@ -339,6 +369,8 @@ describe API::Milestones do ...@@ -339,6 +369,8 @@ describe API::Milestones do
it 'returns merge_requests ordered by position asc' do it 'returns merge_requests ordered by position asc' do
milestone.merge_requests << another_merge_request milestone.merge_requests << another_merge_request
another_merge_request.labels << label_1
merge_request.labels << label_2
get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user) get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user)
......
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