Allow issues to be sorted by relative_position
- adding a "Manual" option to the dropdown - show 100 issues list when manually sorting
This commit is contained in:
parent
2efc284a99
commit
40b67a4f6a
8 changed files with 105 additions and 33 deletions
|
@ -41,6 +41,7 @@ module IssuableCollections
|
|||
return if pagination_disabled?
|
||||
|
||||
@issuables = @issuables.page(params[:page])
|
||||
@issuables = per_page_for_relative_position if params[:sort] == 'relative_position'
|
||||
@issuable_meta_data = issuable_meta_data(@issuables, collection_type)
|
||||
@total_pages = issuable_page_count
|
||||
end
|
||||
|
@ -80,6 +81,11 @@ module IssuableCollections
|
|||
(row_count.to_f / limit).ceil
|
||||
end
|
||||
|
||||
# manual / relative_position sorting allows for 100 items on the page
|
||||
def per_page_for_relative_position
|
||||
@issuables.per(100) # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
end
|
||||
|
||||
def issuable_finder_for(finder_class)
|
||||
finder_class.new(current_user, finder_options)
|
||||
end
|
||||
|
|
|
@ -3,29 +3,30 @@
|
|||
module SortingHelper
|
||||
def sort_options_hash
|
||||
{
|
||||
sort_value_created_date => sort_title_created_date,
|
||||
sort_value_downvotes => sort_title_downvotes,
|
||||
sort_value_due_date => sort_title_due_date,
|
||||
sort_value_due_date_later => sort_title_due_date_later,
|
||||
sort_value_due_date_soon => sort_title_due_date_soon,
|
||||
sort_value_label_priority => sort_title_label_priority,
|
||||
sort_value_largest_group => sort_title_largest_group,
|
||||
sort_value_largest_repo => sort_title_largest_repo,
|
||||
sort_value_milestone => sort_title_milestone,
|
||||
sort_value_milestone_later => sort_title_milestone_later,
|
||||
sort_value_milestone_soon => sort_title_milestone_soon,
|
||||
sort_value_name => sort_title_name,
|
||||
sort_value_name_desc => sort_title_name_desc,
|
||||
sort_value_oldest_created => sort_title_oldest_created,
|
||||
sort_value_oldest_signin => sort_title_oldest_signin,
|
||||
sort_value_oldest_updated => sort_title_oldest_updated,
|
||||
sort_value_recently_created => sort_title_recently_created,
|
||||
sort_value_recently_signin => sort_title_recently_signin,
|
||||
sort_value_recently_updated => sort_title_recently_updated,
|
||||
sort_value_popularity => sort_title_popularity,
|
||||
sort_value_priority => sort_title_priority,
|
||||
sort_value_upvotes => sort_title_upvotes,
|
||||
sort_value_contacted_date => sort_title_contacted_date
|
||||
sort_value_created_date => sort_title_created_date,
|
||||
sort_value_downvotes => sort_title_downvotes,
|
||||
sort_value_due_date => sort_title_due_date,
|
||||
sort_value_due_date_later => sort_title_due_date_later,
|
||||
sort_value_due_date_soon => sort_title_due_date_soon,
|
||||
sort_value_label_priority => sort_title_label_priority,
|
||||
sort_value_largest_group => sort_title_largest_group,
|
||||
sort_value_largest_repo => sort_title_largest_repo,
|
||||
sort_value_milestone => sort_title_milestone,
|
||||
sort_value_milestone_later => sort_title_milestone_later,
|
||||
sort_value_milestone_soon => sort_title_milestone_soon,
|
||||
sort_value_name => sort_title_name,
|
||||
sort_value_name_desc => sort_title_name_desc,
|
||||
sort_value_oldest_created => sort_title_oldest_created,
|
||||
sort_value_oldest_signin => sort_title_oldest_signin,
|
||||
sort_value_oldest_updated => sort_title_oldest_updated,
|
||||
sort_value_recently_created => sort_title_recently_created,
|
||||
sort_value_recently_signin => sort_title_recently_signin,
|
||||
sort_value_recently_updated => sort_title_recently_updated,
|
||||
sort_value_popularity => sort_title_popularity,
|
||||
sort_value_priority => sort_title_priority,
|
||||
sort_value_upvotes => sort_title_upvotes,
|
||||
sort_value_contacted_date => sort_title_contacted_date,
|
||||
sort_value_relative_position => sort_title_relative_position
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -397,6 +398,10 @@ module SortingHelper
|
|||
s_('SortOptions|Recent last activity')
|
||||
end
|
||||
|
||||
def sort_title_relative_position
|
||||
s_('SortOptions|Manual')
|
||||
end
|
||||
|
||||
# Values.
|
||||
def sort_value_access_level_asc
|
||||
'access_level_asc'
|
||||
|
@ -545,4 +550,8 @@ module SortingHelper
|
|||
def sort_value_recently_last_activity
|
||||
'last_activity_on_desc'
|
||||
end
|
||||
|
||||
def sort_value_relative_position
|
||||
'relative_position'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,6 +58,7 @@ class Issue < ApplicationRecord
|
|||
scope :order_due_date_asc, -> { reorder('issues.due_date IS NULL, issues.due_date ASC') }
|
||||
scope :order_due_date_desc, -> { reorder('issues.due_date IS NULL, issues.due_date DESC') }
|
||||
scope :order_closest_future_date, -> { reorder('CASE WHEN issues.due_date >= CURRENT_DATE THEN 0 ELSE 1 END ASC, ABS(CURRENT_DATE - issues.due_date) ASC') }
|
||||
scope :order_relative_position_asc, -> { reorder(::Gitlab::Database.nulls_last_order('relative_position', 'ASC')) }
|
||||
|
||||
scope :preload_associations, -> { preload(:labels, project: :namespace) }
|
||||
scope :with_api_entity_associations, -> { preload(:timelogs, :assignees, :author, :notes, :labels, project: [:route, { namespace: :route }] ) }
|
||||
|
@ -130,9 +131,10 @@ class Issue < ApplicationRecord
|
|||
def self.sort_by_attribute(method, excluded_labels: [])
|
||||
case method.to_s
|
||||
when 'closest_future_date' then order_closest_future_date
|
||||
when 'due_date' then order_due_date_asc
|
||||
when 'due_date_asc' then order_due_date_asc
|
||||
when 'due_date_desc' then order_due_date_desc
|
||||
when 'due_date' then order_due_date_asc
|
||||
when 'due_date_asc' then order_due_date_asc
|
||||
when 'due_date_desc' then order_due_date_desc
|
||||
when 'relative_position' then order_relative_position_asc
|
||||
else
|
||||
super
|
||||
end
|
||||
|
|
|
@ -10,12 +10,13 @@
|
|||
= icon('chevron-down')
|
||||
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
|
||||
%li
|
||||
= sortable_item(sort_title_priority, page_filter_path(sort: sort_value_priority), sort_title)
|
||||
= sortable_item(sort_title_created_date, page_filter_path(sort: sort_value_created_date), sort_title)
|
||||
= sortable_item(sort_title_recently_updated, page_filter_path(sort: sort_value_recently_updated), sort_title)
|
||||
= sortable_item(sort_title_milestone, page_filter_path(sort: sort_value_milestone), sort_title)
|
||||
= sortable_item(sort_title_due_date, page_filter_path(sort: sort_value_due_date), sort_title) if viewing_issues
|
||||
= sortable_item(sort_title_popularity, page_filter_path(sort: sort_value_popularity), sort_title)
|
||||
= sortable_item(sort_title_label_priority, page_filter_path(sort: sort_value_label_priority), sort_title)
|
||||
= sortable_item(sort_title_priority, page_filter_path(sort: sort_value_priority), sort_title)
|
||||
= sortable_item(sort_title_created_date, page_filter_path(sort: sort_value_created_date), sort_title)
|
||||
= sortable_item(sort_title_recently_updated, page_filter_path(sort: sort_value_recently_updated), sort_title)
|
||||
= sortable_item(sort_title_milestone, page_filter_path(sort: sort_value_milestone), sort_title)
|
||||
= sortable_item(sort_title_due_date, page_filter_path(sort: sort_value_due_date), sort_title) if viewing_issues
|
||||
= sortable_item(sort_title_popularity, page_filter_path(sort: sort_value_popularity), sort_title)
|
||||
= sortable_item(sort_title_label_priority, page_filter_path(sort: sort_value_label_priority), sort_title)
|
||||
= sortable_item(sort_title_relative_position, page_filter_path(sort: sort_value_relative_position), sort_title) if viewing_issues
|
||||
= render_if_exists('shared/ee/issuable/sort_dropdown', viewing_issues: viewing_issues, sort_title: sort_title)
|
||||
= issuable_sort_direction_button(sort_value)
|
||||
|
|
5
changelogs/unreleased/9121-sort-relative-position.yml
Normal file
5
changelogs/unreleased/9121-sort-relative-position.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Allow issue list to be sorted by relative order
|
||||
merge_request: 28566
|
||||
author:
|
||||
type: added
|
|
@ -9061,6 +9061,9 @@ msgstr ""
|
|||
msgid "SortOptions|Least popular"
|
||||
msgstr ""
|
||||
|
||||
msgid "SortOptions|Manual"
|
||||
msgstr ""
|
||||
|
||||
msgid "SortOptions|Milestone due date"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -130,6 +130,37 @@ describe Projects::IssuesController do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with relative_position sorting' do
|
||||
let!(:issue_list) { create_list(:issue, 2, project: project) }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
project.add_developer(user)
|
||||
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
|
||||
end
|
||||
|
||||
it 'overrides the number allowed on the page' do
|
||||
get :index,
|
||||
params: {
|
||||
namespace_id: project.namespace.to_param,
|
||||
project_id: project,
|
||||
sort: 'relative_position'
|
||||
}
|
||||
|
||||
expect(assigns(:issues).count).to eq 2
|
||||
end
|
||||
|
||||
it 'allows the default number on the page' do
|
||||
get :index,
|
||||
params: {
|
||||
namespace_id: project.namespace.to_param,
|
||||
project_id: project
|
||||
}
|
||||
|
||||
expect(assigns(:issues).count).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
context 'external authorization' do
|
||||
before do
|
||||
sign_in user
|
||||
|
|
|
@ -93,6 +93,21 @@ describe Issue do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#sort' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
context "by relative_position" do
|
||||
let!(:issue) { create(:issue, project: project) }
|
||||
let!(:issue2) { create(:issue, project: project, relative_position: 2) }
|
||||
let!(:issue3) { create(:issue, project: project, relative_position: 1) }
|
||||
|
||||
it "sorts asc with nulls at the end" do
|
||||
issues = project.issues.sort_by_attribute('relative_position')
|
||||
expect(issues).to eq([issue3, issue2, issue])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#card_attributes' do
|
||||
it 'includes the author name' do
|
||||
allow(subject).to receive(:author).and_return(double(name: 'Robert'))
|
||||
|
|
Loading…
Reference in a new issue