summaryrefslogtreecommitdiff
path: root/app/controllers/concerns/issuable_collections.rb
blob: 4f61e5ed711319c5a2f8679cdfda7e01cc9e55e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# frozen_string_literal: true

module IssuableCollections
  extend ActiveSupport::Concern
  include PaginatedCollection
  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

    unless pagination_disabled?
      set_pagination

      return if redirect_out_of_range(@issuables, @total_pages)
    end

    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
    @issuables          = @issuables.page(params[:page])
    @issuables          = per_page_for_relative_position if params[:sort] == 'relative_position'
    @issuable_meta_data = Gitlab::IssuableMetadata.new(current_user, @issuables).data
    @total_pages        = issuable_page_count(@issuables)
  end
  # rubocop:enable Gitlab/ModuleWithInstanceVariables

  def pagination_disabled?
    false
  end

  # rubocop: disable CodeReuse/ActiveRecord
  def issuables_collection
    finder.execute.preload(preload_for_collection)
  end
  # rubocop: enable CodeReuse/ActiveRecord

  def issuable_page_count(relation)
    page_count_for_relation(relation, finder.row_count)
  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

  # 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] =~ /^#(?<iid>\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 + [:project, project: :namespace]
                                when 'MergeRequest'
                                  common_attributes + [
                                    :target_project, :latest_merge_request_diff, :approvals, :approved_by_users,
                                    source_project: :route, head_pipeline: :project, target_project: :namespace
                                  ]
                                end
  end
  # rubocop:enable Gitlab/ModuleWithInstanceVariables
end

IssuableCollections.prepend_if_ee('EE::IssuableCollections')