Commit f667b284 authored by Andrew Smith's avatar Andrew Smith

Allow sorting issues by their title

Changelog: added
parent 43a9030d
...@@ -20,6 +20,7 @@ const MILESTONE_DUE = 'milestone_due'; ...@@ -20,6 +20,7 @@ const MILESTONE_DUE = 'milestone_due';
const POPULARITY = 'popularity'; const POPULARITY = 'popularity';
const WEIGHT = 'weight'; const WEIGHT = 'weight';
const LABEL_PRIORITY = 'label_priority'; const LABEL_PRIORITY = 'label_priority';
const TITLE = 'title';
export const RELATIVE_POSITION = 'relative_position'; export const RELATIVE_POSITION = 'relative_position';
export const LOADING_LIST_ITEMS_LENGTH = 8; export const LOADING_LIST_ITEMS_LENGTH = 8;
export const PAGE_SIZE = 20; export const PAGE_SIZE = 20;
...@@ -41,6 +42,8 @@ export const sortOrderMap = { ...@@ -41,6 +42,8 @@ export const sortOrderMap = {
relative_position: { order_by: RELATIVE_POSITION, sort: ASC }, relative_position: { order_by: RELATIVE_POSITION, sort: ASC },
weight_desc: { order_by: WEIGHT, sort: DESC }, weight_desc: { order_by: WEIGHT, sort: DESC },
weight: { order_by: WEIGHT, sort: ASC }, weight: { order_by: WEIGHT, sort: ASC },
title: { order_by: TITLE, sort: ASC },
title_desc: { order_by: TITLE, sort: DESC },
}; };
export const availableSortOptionsJira = [ export const availableSortOptionsJira = [
...@@ -144,6 +147,8 @@ export const POPULARITY_DESC = 'POPULARITY_DESC'; ...@@ -144,6 +147,8 @@ export const POPULARITY_DESC = 'POPULARITY_DESC';
export const PRIORITY_ASC = 'PRIORITY_ASC'; export const PRIORITY_ASC = 'PRIORITY_ASC';
export const PRIORITY_DESC = 'PRIORITY_DESC'; export const PRIORITY_DESC = 'PRIORITY_DESC';
export const RELATIVE_POSITION_ASC = 'RELATIVE_POSITION_ASC'; export const RELATIVE_POSITION_ASC = 'RELATIVE_POSITION_ASC';
export const TITLE_ASC = 'TITLE_ASC';
export const TITLE_DESC = 'TITLE_DESC';
export const UPDATED_ASC = 'UPDATED_ASC'; export const UPDATED_ASC = 'UPDATED_ASC';
export const UPDATED_DESC = 'UPDATED_DESC'; export const UPDATED_DESC = 'UPDATED_DESC';
export const WEIGHT_ASC = 'WEIGHT_ASC'; export const WEIGHT_ASC = 'WEIGHT_ASC';
...@@ -161,6 +166,7 @@ const LABEL_PRIORITY_ASC_SORT = 'label_priority_asc'; ...@@ -161,6 +166,7 @@ const LABEL_PRIORITY_ASC_SORT = 'label_priority_asc';
const POPULARITY_ASC_SORT = 'popularity_asc'; const POPULARITY_ASC_SORT = 'popularity_asc';
const WEIGHT_DESC_SORT = 'weight_desc'; const WEIGHT_DESC_SORT = 'weight_desc';
const BLOCKING_ISSUES_DESC_SORT = 'blocking_issues_desc'; const BLOCKING_ISSUES_DESC_SORT = 'blocking_issues_desc';
const TITLE_DESC_SORT = 'title_desc';
export const urlSortParams = { export const urlSortParams = {
[PRIORITY_ASC]: PRIORITY_ASC_SORT, [PRIORITY_ASC]: PRIORITY_ASC_SORT,
...@@ -181,6 +187,8 @@ export const urlSortParams = { ...@@ -181,6 +187,8 @@ export const urlSortParams = {
[WEIGHT_ASC]: WEIGHT, [WEIGHT_ASC]: WEIGHT,
[WEIGHT_DESC]: WEIGHT_DESC_SORT, [WEIGHT_DESC]: WEIGHT_DESC_SORT,
[BLOCKING_ISSUES_DESC]: BLOCKING_ISSUES_DESC_SORT, [BLOCKING_ISSUES_DESC]: BLOCKING_ISSUES_DESC_SORT,
[TITLE_ASC]: TITLE,
[TITLE_DESC]: TITLE_DESC_SORT,
}; };
export const MAX_LIST_SIZE = 10; export const MAX_LIST_SIZE = 10;
......
...@@ -10,6 +10,8 @@ module Types ...@@ -10,6 +10,8 @@ module Types
value 'RELATIVE_POSITION_ASC', 'Relative position by ascending order.', value: :relative_position_asc value 'RELATIVE_POSITION_ASC', 'Relative position by ascending order.', value: :relative_position_asc
value 'SEVERITY_ASC', 'Severity from less critical to more critical.', value: :severity_asc value 'SEVERITY_ASC', 'Severity from less critical to more critical.', value: :severity_asc
value 'SEVERITY_DESC', 'Severity from more critical to less critical.', value: :severity_desc value 'SEVERITY_DESC', 'Severity from more critical to less critical.', value: :severity_desc
value 'TITLE_ASC', 'Title by ascending order.', value: :title_asc
value 'TITLE_DESC', 'Title by descending order.', value: :title_desc
value 'POPULARITY_ASC', 'Number of upvotes (awarded "thumbs up" emoji) by ascending order.', value: :popularity_asc value 'POPULARITY_ASC', 'Number of upvotes (awarded "thumbs up" emoji) by ascending order.', value: :popularity_asc
value 'POPULARITY_DESC', 'Number of upvotes (awarded "thumbs up" emoji) by descending order.', value: :popularity_desc value 'POPULARITY_DESC', 'Number of upvotes (awarded "thumbs up" emoji) by descending order.', value: :popularity_desc
end end
......
...@@ -37,7 +37,8 @@ module SortingHelper ...@@ -37,7 +37,8 @@ module SortingHelper
sort_value_contacted_date => sort_title_contacted_date, sort_value_contacted_date => sort_title_contacted_date,
sort_value_relative_position => sort_title_relative_position, sort_value_relative_position => sort_title_relative_position,
sort_value_size => sort_title_size, sort_value_size => sort_title_size,
sort_value_expire_date => sort_title_expire_date sort_value_expire_date => sort_title_expire_date,
sort_value_title => sort_title_title
} }
end end
# rubocop: enable Metrics/AbcSize # rubocop: enable Metrics/AbcSize
...@@ -188,7 +189,8 @@ module SortingHelper ...@@ -188,7 +189,8 @@ module SortingHelper
sort_value_due_date_later => sort_value_due_date, sort_value_due_date_later => sort_value_due_date,
sort_value_merged_recently => sort_value_merged_date, sort_value_merged_recently => sort_value_merged_date,
sort_value_closed_recently => sort_value_closed_date, sort_value_closed_recently => sort_value_closed_date,
sort_value_least_popular => sort_value_popularity sort_value_least_popular => sort_value_popularity,
sort_value_title_desc => sort_value_title
} }
end end
...@@ -205,7 +207,8 @@ module SortingHelper ...@@ -205,7 +207,8 @@ module SortingHelper
sort_value_closed_date => sort_value_closed_recently, sort_value_closed_date => sort_value_closed_recently,
sort_value_closed_earlier => sort_value_closed_recently, sort_value_closed_earlier => sort_value_closed_recently,
sort_value_popularity => sort_value_least_popular, sort_value_popularity => sort_value_least_popular,
sort_value_most_popular => sort_value_least_popular sort_value_most_popular => sort_value_least_popular,
sort_value_title => sort_value_title_desc
}.merge(issuable_sort_option_overrides) }.merge(issuable_sort_option_overrides)
end end
......
...@@ -138,6 +138,10 @@ module SortingTitlesValuesHelper ...@@ -138,6 +138,10 @@ module SortingTitlesValuesHelper
s_('SortOptions|Start soon') s_('SortOptions|Start soon')
end end
def sort_title_title
s_('SortOptions|Title')
end
def sort_title_upvotes def sort_title_upvotes
s_('SortOptions|Most popular') s_('SortOptions|Most popular')
end end
...@@ -307,6 +311,14 @@ module SortingTitlesValuesHelper ...@@ -307,6 +311,14 @@ module SortingTitlesValuesHelper
'start_date_asc' 'start_date_asc'
end end
def sort_value_title
'title_asc'
end
def sort_value_title_desc
'title_desc'
end
def sort_value_upvotes def sort_value_upvotes
'upvotes_desc' 'upvotes_desc'
end end
......
...@@ -26,6 +26,7 @@ module Issuable ...@@ -26,6 +26,7 @@ module Issuable
include UpdatedAtFilterable include UpdatedAtFilterable
include ClosedAtFilterable include ClosedAtFilterable
include VersionedDescription include VersionedDescription
include SortableTitle
TITLE_LENGTH_MAX = 255 TITLE_LENGTH_MAX = 255
TITLE_HTML_LENGTH_MAX = 800 TITLE_HTML_LENGTH_MAX = 800
...@@ -293,6 +294,8 @@ module Issuable ...@@ -293,6 +294,8 @@ module Issuable
when 'popularity', 'popularity_desc', 'upvotes_desc' then order_upvotes_desc when 'popularity', 'popularity_desc', 'upvotes_desc' then order_upvotes_desc
when 'priority', 'priority_asc' then order_due_date_and_labels_priority(excluded_labels: excluded_labels) when 'priority', 'priority_asc' then order_due_date_and_labels_priority(excluded_labels: excluded_labels)
when 'priority_desc' then order_due_date_and_labels_priority('DESC', excluded_labels: excluded_labels) when 'priority_desc' then order_due_date_and_labels_priority('DESC', excluded_labels: excluded_labels)
when 'title_asc' then order_title_asc.with_order_id_desc
when 'title_desc' then order_title_desc.with_order_id_desc
else order_by(method) else order_by(method)
end end
......
# frozen_string_literal: true
module SortableTitle
extend ActiveSupport::Concern
included do
scope :order_title_asc, -> { reorder(Arel::Nodes::Ascending.new(arel_table[:title].lower)) }
scope :order_title_desc, -> { reorder(Arel::Nodes::Descending.new(arel_table[:title].lower)) }
end
class_methods do
def simple_sorts
super.merge(
{
'title_asc' => -> { order_title_asc },
'title_desc' => -> { order_title_desc }
}
)
end
end
end
...@@ -21,5 +21,6 @@ ...@@ -21,5 +21,6 @@
= sortable_item(sort_title_merged_date, page_filter_path(sort: sort_value_merged_date), sort_title) if viewing_merge_requests = sortable_item(sort_title_merged_date, page_filter_path(sort: sort_value_merged_date), sort_title) if viewing_merge_requests
= sortable_item(sort_title_closed_date, page_filter_path(sort: sort_value_closed_date), sort_title) if viewing_merge_requests = sortable_item(sort_title_closed_date, page_filter_path(sort: sort_value_closed_date), sort_title) if viewing_merge_requests
= sortable_item(sort_title_relative_position, page_filter_path(sort: sort_value_relative_position), sort_title) if viewing_issues = sortable_item(sort_title_relative_position, page_filter_path(sort: sort_value_relative_position), sort_title) if viewing_issues
= sortable_item(sort_title_title, page_filter_path(sort: sort_value_title), sort_title) if viewing_issues
= render_if_exists('shared/ee/issuable/sort_dropdown', viewing_issues: viewing_issues, sort_title: sort_title) = render_if_exists('shared/ee/issuable/sort_dropdown', viewing_issues: viewing_issues, sort_title: sort_title)
= issuable_sort_direction_button(sort_value) = issuable_sort_direction_button(sort_value)
...@@ -15484,6 +15484,8 @@ Values for sorting issues. ...@@ -15484,6 +15484,8 @@ Values for sorting issues.
| <a id="issuesortseverity_desc"></a>`SEVERITY_DESC` | Severity from more critical to less critical. | | <a id="issuesortseverity_desc"></a>`SEVERITY_DESC` | Severity from more critical to less critical. |
| <a id="issuesortsla_due_at_asc"></a>`SLA_DUE_AT_ASC` | Issues with earliest SLA due time shown first. | | <a id="issuesortsla_due_at_asc"></a>`SLA_DUE_AT_ASC` | Issues with earliest SLA due time shown first. |
| <a id="issuesortsla_due_at_desc"></a>`SLA_DUE_AT_DESC` | Issues with latest SLA due time shown first. | | <a id="issuesortsla_due_at_desc"></a>`SLA_DUE_AT_DESC` | Issues with latest SLA due time shown first. |
| <a id="issuesorttitle_asc"></a>`TITLE_ASC` | Title by ascending order. |
| <a id="issuesorttitle_desc"></a>`TITLE_DESC` | Title by descending order. |
| <a id="issuesortupdated_asc"></a>`UPDATED_ASC` | Updated at ascending order. | | <a id="issuesortupdated_asc"></a>`UPDATED_ASC` | Updated at ascending order. |
| <a id="issuesortupdated_desc"></a>`UPDATED_DESC` | Updated at descending order. | | <a id="issuesortupdated_desc"></a>`UPDATED_DESC` | Updated at descending order. |
| <a id="issuesortweight_asc"></a>`WEIGHT_ASC` | Weight by ascending order. | | <a id="issuesortweight_asc"></a>`WEIGHT_ASC` | Weight by ascending order. |
......
...@@ -73,7 +73,7 @@ GET /issues?state=opened ...@@ -73,7 +73,7 @@ GET /issues?state=opened
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14016) in GitLab 10.0)_ | | `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14016) in GitLab 10.0)_ |
| `non_archived` | boolean | no | Return issues only from non-archived projects. If `false`, the response returns issues from both archived and non-archived projects. Default is `true`. _(Introduced in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/197170))_ | | `non_archived` | boolean | no | Return issues only from non-archived projects. If `false`, the response returns issues from both archived and non-archived projects. Default is `true`. _(Introduced in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/197170))_ |
| `not` | Hash | no | Return issues that do not match the parameters supplied. Accepts: `assignee_id`, `assignee_username`, `author_id`, `author_username`, `iids`, `iteration_id`, `iteration_title`, `labels`, `milestone`, `milestone_id` and `weight`. | | `not` | Hash | no | Return issues that do not match the parameters supplied. Accepts: `assignee_id`, `assignee_username`, `author_id`, `author_username`, `iids`, `iteration_id`, `iteration_title`, `labels`, `milestone`, `milestone_id` and `weight`. |
| `order_by` | string | no | Return issues ordered by `created_at`, `updated_at`, `priority`, `due_date`, `relative_position`, `label_priority`, `milestone_due`, `popularity`, `weight` fields. Default is `created_at` | | `order_by` | string | no | Return issues ordered by `created_at`, `due_date`, `label_priority`, `milestone_due`, `popularity`, `priority`, `relative_position`, `title`, `updated_at`, or `weight` fields. Default is `created_at`. |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. Defaults to `created_by_me`<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5. [Changed to snake_case](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18935) in GitLab 11.0)_ | | `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. Defaults to `created_by_me`<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5. [Changed to snake_case](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18935) in GitLab 11.0)_ |
| `search` | string | no | Search issues against their `title` and `description` | | `search` | string | no | Search issues against their `title` and `description` |
| `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` | | `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` |
......
...@@ -37,10 +37,6 @@ module EE ...@@ -37,10 +37,6 @@ module EE
s_('SortOptions|Type') s_('SortOptions|Type')
end end
def sort_title_title
s_('SortOptions|Title')
end
def sort_value_start_date def sort_value_start_date
'start_date_asc' 'start_date_asc'
end end
...@@ -49,14 +45,6 @@ module EE ...@@ -49,14 +45,6 @@ module EE
'end_date_asc' 'end_date_asc'
end end
def sort_value_title
'title_asc'
end
def sort_value_title_desc
'title_desc'
end
def sort_value_end_date_later def sort_value_end_date_later
'end_date_desc' 'end_date_desc'
end end
......
...@@ -19,6 +19,7 @@ module EE ...@@ -19,6 +19,7 @@ module EE
include Presentable include Presentable
include IdInOrdered include IdInOrdered
include Todoable include Todoable
include SortableTitle
enum state_id: { enum state_id: {
opened: ::Epic.available_states[:opened], opened: ::Epic.available_states[:opened],
...@@ -112,9 +113,6 @@ module EE ...@@ -112,9 +113,6 @@ module EE
reorder(keyset_order) reorder(keyset_order)
end end
scope :order_title_asc, -> { reorder(Arel::Nodes::Ascending.new(arel_table[:title].lower)) }
scope :order_title_desc, -> { reorder(Arel::Nodes::Descending.new(arel_table[:title].lower)) }
scope :order_closed_date_desc, -> { reorder(closed_at: :desc) } scope :order_closed_date_desc, -> { reorder(closed_at: :desc) }
scope :order_relative_position, -> do scope :order_relative_position, -> do
...@@ -277,9 +275,7 @@ module EE ...@@ -277,9 +275,7 @@ module EE
'start_date_asc' => -> { order_start_date_asc }, 'start_date_asc' => -> { order_start_date_asc },
'start_date_desc' => -> { order_start_date_desc }, 'start_date_desc' => -> { order_start_date_desc },
'end_date_asc' => -> { order_end_date_asc }, 'end_date_asc' => -> { order_end_date_asc },
'end_date_desc' => -> { order_end_date_desc }, 'end_date_desc' => -> { order_end_date_desc }
'title_asc' => -> { order_title_asc },
'title_desc' => -> { order_title_desc }
} }
) )
end end
......
...@@ -381,11 +381,11 @@ RSpec.describe Issue do ...@@ -381,11 +381,11 @@ RSpec.describe Issue do
describe '.simple_sorts' do describe '.simple_sorts' do
it 'includes weight with other base keys' do it 'includes weight with other base keys' do
expect(Issue.simple_sorts.keys).to match_array( expect(Issue.simple_sorts.keys).to match_array(
%w(created_asc created_at_asc created_date created_desc created_at_desc %w(closest_future_date closest_future_date_asc created_asc
closest_future_date closest_future_date_asc due_date due_date_asc due_date_desc created_at_asc created_at_desc created_date created_desc due_date
id_asc id_desc relative_position relative_position_asc due_date_asc due_date_desc id_asc id_desc relative_position
updated_desc updated_asc updated_at_asc updated_at_desc relative_position_asc title_asc title_desc updated_asc updated_at_asc
weight weight_asc weight_desc)) updated_at_desc updated_desc weight weight_asc weight_desc))
end end
end end
......
...@@ -34,7 +34,17 @@ module API ...@@ -34,7 +34,17 @@ module API
end end
def self.sort_options def self.sort_options
%w[created_at updated_at priority due_date relative_position label_priority milestone_due popularity] %w[
created_at
due_date
label_priority
milestone_due
popularity
priority
relative_position
title
updated_at
]
end end
def issue_finder(args = {}) def issue_finder(args = {})
......
...@@ -78,7 +78,7 @@ module API ...@@ -78,7 +78,7 @@ module API
optional :state, type: String, values: %w[opened closed all], default: 'all', optional :state, type: String, values: %w[opened closed all], default: 'all',
desc: 'Return opened, closed, or all issues' desc: 'Return opened, closed, or all issues'
optional :order_by, type: String, values: Helpers::IssuesHelpers.sort_options, default: 'created_at', optional :order_by, type: String, values: Helpers::IssuesHelpers.sort_options, default: 'created_at',
desc: 'Return issues ordered by `created_at` or `updated_at` fields.' desc: 'Return issues ordered by `created_at`, `due_date`, `label_priority`, `milestone_due`, `popularity`, `priority`, `relative_position`, `title`, or `updated_at` fields.'
optional :sort, type: String, values: %w[asc desc], default: 'desc', optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return issues sorted in `asc` or `desc` order.' desc: 'Return issues sorted in `asc` or `desc` order.'
optional :due_date, type: String, values: %w[0 overdue week month next_month_and_previous_two_weeks] << '', optional :due_date, type: String, values: %w[0 overdue week month next_month_and_previous_two_weeks] << '',
......
...@@ -414,6 +414,22 @@ RSpec.describe Resolvers::IssuesResolver do ...@@ -414,6 +414,22 @@ RSpec.describe Resolvers::IssuesResolver do
end end
end end
end end
context 'when sorting by title' do
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue1) { create(:issue, project: project, title: 'foo') }
let_it_be(:issue2) { create(:issue, project: project, title: 'bar') }
let_it_be(:issue3) { create(:issue, project: project, title: 'baz') }
let_it_be(:issue4) { create(:issue, project: project, title: 'Baz 2') }
it 'sorts issues ascending' do
expect(resolve_issues(sort: :title_asc).to_a).to eq [issue2, issue3, issue4, issue1]
end
it 'sorts issues descending' do
expect(resolve_issues(sort: :title_desc).to_a).to eq [issue1, issue4, issue3, issue2]
end
end
end end
it 'returns issues user can see' do it 'returns issues user can see' do
......
...@@ -368,6 +368,23 @@ RSpec.describe Issuable do ...@@ -368,6 +368,23 @@ RSpec.describe Issuable do
expect(sorted_issue_ids).to eq(sorted_issue_ids.uniq) expect(sorted_issue_ids).to eq(sorted_issue_ids.uniq)
end end
end end
context 'by title' do
let!(:issue1) { create(:issue, project: project, title: 'foo') }
let!(:issue2) { create(:issue, project: project, title: 'bar') }
let!(:issue3) { create(:issue, project: project, title: 'baz') }
let!(:issue4) { create(:issue, project: project, title: 'Baz 2') }
it 'sorts asc' do
issues = project.issues.sort_by_attribute('title_asc')
expect(issues).to eq([issue2, issue3, issue4, issue1])
end
it 'sorts desc' do
issues = project.issues.sort_by_attribute('title_desc')
expect(issues).to eq([issue1, issue4, issue3, issue2])
end
end
end end
describe '#subscribed?' do describe '#subscribed?' do
......
...@@ -165,8 +165,8 @@ RSpec.describe Issue do ...@@ -165,8 +165,8 @@ RSpec.describe Issue do
expect(described_class.simple_sorts.keys).to include( expect(described_class.simple_sorts.keys).to include(
*%w(created_asc created_at_asc created_date created_desc created_at_desc *%w(created_asc created_at_asc created_date created_desc created_at_desc
closest_future_date closest_future_date_asc due_date due_date_asc due_date_desc closest_future_date closest_future_date_asc due_date due_date_asc due_date_desc
id_asc id_desc relative_position relative_position_asc id_asc id_desc relative_position relative_position_asc updated_desc updated_asc
updated_desc updated_asc updated_at_asc updated_at_desc)) updated_at_asc updated_at_desc title_asc title_desc))
end end
end end
...@@ -203,6 +203,25 @@ RSpec.describe Issue do ...@@ -203,6 +203,25 @@ RSpec.describe Issue do
end end
end end
describe '.order_title' do
let_it_be(:issue1) { create(:issue, title: 'foo') }
let_it_be(:issue2) { create(:issue, title: 'bar') }
let_it_be(:issue3) { create(:issue, title: 'baz') }
let_it_be(:issue4) { create(:issue, title: 'Baz 2') }
context 'sorting ascending' do
subject { described_class.order_title_asc }
it { is_expected.to eq([issue2, issue3, issue4, issue1]) }
end
context 'sorting descending' do
subject { described_class.order_title_desc }
it { is_expected.to eq([issue1, issue4, issue3, issue2]) }
end
end
describe '#order_by_position_and_priority' do describe '#order_by_position_and_priority' do
let(:project) { reusable_project } let(:project) { reusable_project }
let(:p1) { create(:label, title: 'P1', project: project, priority: 1) } let(:p1) { create(:label, title: 'P1', project: project, priority: 1) }
......
...@@ -815,6 +815,18 @@ RSpec.describe API::Issues do ...@@ -815,6 +815,18 @@ RSpec.describe API::Issues do
expect_paginated_array_response([closed_issue.id, issue.id]) expect_paginated_array_response([closed_issue.id, issue.id])
end end
it 'sorts by title asc when requested' do
get api('/issues', user), params: { order_by: :title, sort: :asc }
expect_paginated_array_response([issue.id, closed_issue.id])
end
it 'sorts by title desc when requested' do
get api('/issues', user), params: { order_by: :title, sort: :desc }
expect_paginated_array_response([closed_issue.id, issue.id])
end
context 'with issues list sort options' do context 'with issues list sort options' do
it 'accepts only predefined order by params' do it 'accepts only predefined order by params' do
API::Helpers::IssuesHelpers.sort_options.each do |sort_opt| API::Helpers::IssuesHelpers.sort_options.each do |sort_opt|
...@@ -824,7 +836,7 @@ RSpec.describe API::Issues do ...@@ -824,7 +836,7 @@ RSpec.describe API::Issues do
end end
it 'fails to sort with non predefined options' do it 'fails to sort with non predefined options' do
%w(milestone title abracadabra).each do |sort_opt| %w(milestone abracadabra).each do |sort_opt|
get api('/issues', user), params: { order_by: sort_opt, sort: 'asc' } get api('/issues', user), params: { order_by: sort_opt, sort: 'asc' }
expect(response).to have_gitlab_http_status(:bad_request) expect(response).to have_gitlab_http_status(:bad_request)
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