2016-07-23 19:28:12 -04:00
|
|
|
module IssuableCollections
|
|
|
|
extend ActiveSupport::Concern
|
|
|
|
include SortingHelper
|
2017-07-08 02:21:09 -04:00
|
|
|
include Gitlab::IssuableMetadata
|
2017-11-17 07:27:16 -05:00
|
|
|
include Gitlab::Utils::StrongMemoize
|
2016-07-23 19:28:12 -04:00
|
|
|
|
|
|
|
included do
|
2017-11-07 08:34:12 -05:00
|
|
|
helper_method :finder
|
2016-07-23 19:28:12 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2017-11-22 02:50:36 -05:00
|
|
|
# rubocop:disable Gitlab/ModuleWithInstanceVariables
|
2017-11-07 08:34:12 -05:00
|
|
|
def set_issuables_index
|
2018-01-29 10:22:58 -05:00
|
|
|
@issuables = issuables_collection
|
2017-09-05 05:22:37 -04:00
|
|
|
|
2018-01-29 10:22:58 -05:00
|
|
|
set_pagination
|
2017-11-07 08:34:12 -05:00
|
|
|
return if redirect_out_of_range(@total_pages)
|
2017-09-05 05:22:37 -04:00
|
|
|
|
|
|
|
if params[:label_name].present?
|
2017-11-07 08:34:12 -05:00
|
|
|
labels_params = { project_id: @project.id, title: params[:label_name] }
|
|
|
|
@labels = LabelsFinder.new(current_user, labels_params).execute
|
2017-09-05 05:22:37 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
@users = []
|
2017-11-07 08:34:12 -05:00
|
|
|
if params[:assignee_id].present?
|
|
|
|
assignee = User.find_by_id(params[:assignee_id])
|
|
|
|
@users.push(assignee) if assignee
|
|
|
|
end
|
2016-07-23 19:28:12 -04:00
|
|
|
|
2017-11-07 08:34:12 -05:00
|
|
|
if params[:author_id].present?
|
|
|
|
author = User.find_by_id(params[:author_id])
|
|
|
|
@users.push(author) if author
|
|
|
|
end
|
2016-07-23 19:28:12 -04:00
|
|
|
end
|
2018-01-29 10:22:58 -05:00
|
|
|
|
|
|
|
def set_pagination
|
|
|
|
return if pagination_disabled?
|
|
|
|
|
|
|
|
@issuables = @issuables.page(params[:page])
|
|
|
|
@issuable_meta_data = issuable_meta_data(@issuables, collection_type)
|
|
|
|
@total_pages = issuable_page_count
|
|
|
|
end
|
2017-11-22 02:50:36 -05:00
|
|
|
# rubocop:enable Gitlab/ModuleWithInstanceVariables
|
2016-07-23 19:28:12 -04:00
|
|
|
|
2018-01-29 10:22:58 -05:00
|
|
|
def pagination_disabled?
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
2017-11-07 08:34:12 -05:00
|
|
|
def issuables_collection
|
|
|
|
finder.execute.preload(preload_for_collection)
|
2016-07-23 19:28:12 -04:00
|
|
|
end
|
|
|
|
|
2017-11-07 08:34:12 -05:00
|
|
|
def redirect_out_of_range(total_pages)
|
2018-01-29 10:22:58 -05:00
|
|
|
return false if total_pages.nil? || total_pages.zero?
|
2017-08-24 12:17:04 -04:00
|
|
|
|
2017-11-22 02:50:36 -05:00
|
|
|
out_of_range = @issuables.current_page > total_pages # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
2017-08-24 12:17:04 -04:00
|
|
|
|
|
|
|
if out_of_range
|
|
|
|
redirect_to(url_for(params.merge(page: total_pages, only_path: true)))
|
|
|
|
end
|
|
|
|
|
|
|
|
out_of_range
|
|
|
|
end
|
|
|
|
|
2017-11-07 08:34:12 -05:00
|
|
|
def issuable_page_count
|
2017-11-22 02:50:36 -05:00
|
|
|
page_count_for_relation(@issuables, finder.row_count) # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
2017-08-24 12:17:04 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def page_count_for_relation(relation, row_count)
|
|
|
|
limit = relation.limit_value.to_f
|
|
|
|
|
|
|
|
return 1 if limit.zero?
|
|
|
|
|
|
|
|
(row_count.to_f / limit).ceil
|
|
|
|
end
|
|
|
|
|
2016-07-23 19:28:12 -04:00
|
|
|
def issuable_finder_for(finder_class)
|
|
|
|
finder_class.new(current_user, filter_params)
|
|
|
|
end
|
|
|
|
|
2017-11-22 02:50:36 -05:00
|
|
|
# rubocop:disable Gitlab/ModuleWithInstanceVariables
|
2016-07-23 19:28:12 -04:00
|
|
|
def filter_params
|
|
|
|
set_sort_order_from_cookie
|
|
|
|
set_default_state
|
|
|
|
|
2017-07-11 12:11:41 -04:00
|
|
|
# Skip irrelevant Rails routing params
|
|
|
|
@filter_params = params.dup.except(:controller, :action, :namespace_id)
|
2016-07-23 19:28:12 -04:00
|
|
|
@filter_params[:sort] ||= default_sort_order
|
|
|
|
|
|
|
|
@sort = @filter_params[:sort]
|
|
|
|
|
|
|
|
if @project
|
|
|
|
@filter_params[:project_id] = @project.id
|
|
|
|
elsif @group
|
|
|
|
@filter_params[:group_id] = @group.id
|
2018-01-24 01:06:24 -05:00
|
|
|
@filter_params[:include_subgroups] = true
|
2016-07-23 19:28:12 -04:00
|
|
|
else
|
|
|
|
# TODO: this filter ignore issues/mr created in public or
|
|
|
|
# internal repos where you are not a member. Enable this filter
|
|
|
|
# or improve current implementation to filter only issues you
|
|
|
|
# created or assigned or mentioned
|
|
|
|
# @filter_params[:authorized_only] = true
|
|
|
|
end
|
|
|
|
|
2017-09-15 12:20:29 -04:00
|
|
|
@filter_params.permit(IssuableFinder::VALID_PARAMS)
|
2016-07-23 19:28:12 -04:00
|
|
|
end
|
2017-11-22 02:50:36 -05:00
|
|
|
# rubocop:enable Gitlab/ModuleWithInstanceVariables
|
2016-07-23 19:28:12 -04:00
|
|
|
|
|
|
|
def set_default_state
|
|
|
|
params[:state] = 'opened' if params[:state].blank?
|
|
|
|
end
|
|
|
|
|
|
|
|
def set_sort_order_from_cookie
|
|
|
|
key = 'issuable_sort'
|
|
|
|
|
|
|
|
cookies[key] = params[:sort] if params[:sort].present?
|
2017-09-22 20:46:53 -04:00
|
|
|
cookies[key] = update_cookie_value(cookies[key])
|
2016-07-23 19:28:12 -04:00
|
|
|
params[:sort] = cookies[key]
|
|
|
|
end
|
|
|
|
|
|
|
|
def default_sort_order
|
|
|
|
case params[:state]
|
2017-09-22 20:46:53 -04:00
|
|
|
when 'opened', 'all' then sort_value_created_date
|
2016-07-23 19:28:12 -04:00
|
|
|
when 'merged', 'closed' then sort_value_recently_updated
|
2017-09-22 20:46:53 -04:00
|
|
|
else sort_value_created_date
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Update old values to the actual ones.
|
|
|
|
def update_cookie_value(value)
|
|
|
|
case value
|
|
|
|
when 'id_asc' then sort_value_oldest_created
|
|
|
|
when 'id_desc' then sort_value_recently_created
|
|
|
|
when 'created_asc' then sort_value_created_date
|
|
|
|
when 'created_desc' then sort_value_created_date
|
|
|
|
when 'due_date_asc' then sort_value_due_date
|
|
|
|
when 'due_date_desc' then sort_value_due_date
|
|
|
|
when 'milestone_due_asc' then sort_value_milestone
|
|
|
|
when 'milestone_due_desc' then sort_value_milestone
|
|
|
|
when 'downvotes_asc' then sort_value_popularity
|
|
|
|
when 'downvotes_desc' then sort_value_popularity
|
|
|
|
else value
|
2016-07-23 19:28:12 -04:00
|
|
|
end
|
|
|
|
end
|
2017-11-07 08:34:12 -05:00
|
|
|
|
|
|
|
def finder
|
2017-11-17 07:27:16 -05:00
|
|
|
strong_memoize(:finder) do
|
2017-11-22 02:50:36 -05:00
|
|
|
issuable_finder_for(@finder_type) # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
2017-11-17 07:27:16 -05:00
|
|
|
end
|
2017-11-07 08:34:12 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def collection_type
|
|
|
|
@collection_type ||= case finder
|
|
|
|
when IssuesFinder
|
|
|
|
'Issue'
|
|
|
|
when MergeRequestsFinder
|
|
|
|
'MergeRequest'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def preload_for_collection
|
|
|
|
@preload_for_collection ||= case collection_type
|
|
|
|
when 'Issue'
|
|
|
|
[:project, :author, :assignees, :labels, :milestone, project: :namespace]
|
|
|
|
when 'MergeRequest'
|
|
|
|
[
|
|
|
|
:source_project, :target_project, :author, :assignee, :labels, :milestone,
|
Use latest_merge_request_diff association
Compared to the merge_request_diff association:
1. It's simpler to query. The query uses a foreign key to the
merge_request_diffs table, so no ordering is necessary.
2. It's faster for preloading. The merge_request_diff association has to load
every diff for the MRs in the set, then discard all but the most recent for
each. This association means that Rails can just query for N diffs from N
MRs.
3. It's more complicated to update. This is a bidirectional foreign key, so we
need to update two tables when adding a diff record. This also means we need
to handle this as a special case when importing a GitLab project.
There is some juggling with this association in the merge request model:
* `MergeRequest#latest_merge_request_diff` is _always_ the latest diff.
* `MergeRequest#merge_request_diff` reuses
`MergeRequest#latest_merge_request_diff` unless:
* Arguments are passed. These are typically to force-reload the association.
* It doesn't exist. That means we might be trying to implicitly create a
diff. This only seems to happen in specs.
* The association is already loaded. This is important for the reasons
explained in the comment, which I'll reiterate here: if we a) load a
non-latest diff, then b) get its `merge_request`, then c) get that MR's
`merge_request_diff`, we should get the diff we loaded in c), even though
that's not the latest diff.
Basically, `MergeRequest#merge_request_diff` is the latest diff in most cases,
but not quite all.
2017-11-15 12:22:18 -05:00
|
|
|
head_pipeline: :project, target_project: :namespace, latest_merge_request_diff: :merge_request_diff_commits
|
2017-11-07 08:34:12 -05:00
|
|
|
]
|
|
|
|
end
|
|
|
|
end
|
2016-07-23 19:28:12 -04:00
|
|
|
end
|