# frozen_string_literal: true module IssuableCollections extend ActiveSupport::Concern include PaginatedCollection include SearchRateLimitable include SortingHelper include SortingPreference include Gitlab::Utils::StrongMemoize included do helper_method :finder end private # rubocop:disable Gitlab/ModuleWithInstanceVariables def set_issuables_index @issuables = issuables_collection set_pagination return if redirect_out_of_range(@issuables, @total_pages) if params[:label_name].present? && @project labels_params = { project_id: @project.id, title: params[:label_name] } @labels = LabelsFinder.new(current_user, labels_params).execute end @users = [] if params[:assignee_id].present? assignee = User.find_by_id(params[:assignee_id]) @users.push(assignee) if assignee end if params[:author_id].present? author = User.find_by_id(params[:author_id]) @users.push(author) if author end end def set_pagination row_count = finder.row_count @issuables = @issuables.page(params[:page]) @issuables = per_page_for_relative_position if params[:sort] == 'relative_position' @issuables = @issuables.without_count if row_count == -1 @issuable_meta_data = Gitlab::IssuableMetadata.new(current_user, @issuables).data @total_pages = page_count_for_relation(@issuables, row_count) end # rubocop:enable Gitlab/ModuleWithInstanceVariables # rubocop: disable CodeReuse/ActiveRecord def issuables_collection finder.execute.preload(preload_for_collection) end # rubocop: enable CodeReuse/ActiveRecord def page_count_for_relation(relation, row_count) limit = relation.limit_value.to_f return 1 if limit == 0 return (params[:page] || 1).to_i + 1 if row_count == -1 (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 # rubocop:disable Gitlab/ModuleWithInstanceVariables def finder_options strong_memoize(:finder_options) do params[:state] = default_state if params[:state].blank? options = { scope: params[:scope], state: params[:state], confidential: Gitlab::Utils.to_boolean(params[:confidential]), sort: set_sort_order } # Used by view to highlight active option @sort = options[:sort] # When a user looks for an exact iid, we do not filter by search but only by iid if params[:search] =~ /^#(?\d+)\z/ options[:iids] = Regexp.last_match[:iid] params[:search] = nil end if @project options[:project_id] = @project.id options[:attempt_project_search_optimizations] = true elsif @group options[:group_id] = @group.id options[:include_subgroups] = true options[:attempt_group_search_optimizations] = true end params.permit(finder_type.valid_params).merge(options) end end # rubocop:enable Gitlab/ModuleWithInstanceVariables def default_state 'opened' end def legacy_sort_cookie_name 'issuable_sort' end def default_sort_order case params[:state] when 'opened', 'all' then sort_value_created_date when 'merged', 'closed' then sort_value_recently_updated else sort_value_created_date end end def finder @finder ||= issuable_finder_for(finder_type) end def collection_type @collection_type ||= if finder_type <= IssuesFinder 'Issue' elsif finder_type <= MergeRequestsFinder 'MergeRequest' end end # rubocop:disable Gitlab/ModuleWithInstanceVariables def preload_for_collection common_attributes = [:author, :assignees, :labels, :milestone] @preload_for_collection ||= case collection_type when 'Issue' common_attributes + [:work_item_type, :project, project: :namespace] when 'MergeRequest' common_attributes + [ :target_project, :latest_merge_request_diff, :approvals, :approved_by_users, :reviewers, source_project: :route, head_pipeline: :project, target_project: :namespace ] end end # rubocop:enable Gitlab/ModuleWithInstanceVariables end IssuableCollections.prepend_mod_with('IssuableCollections')