Read about our upcoming Code of Conduct on this issue

issuable_collections.rb 4.74 KB
Newer Older
1
2
# frozen_string_literal: true

3
4
5
module IssuableCollections
  extend ActiveSupport::Concern
  include SortingHelper
George Koltsov's avatar
George Koltsov committed
6
  include SortingPreference
7
  include Gitlab::IssuableMetadata
8
  include Gitlab::Utils::StrongMemoize
9
10

  included do
11
    helper_method :finder
12
13
14
15
  end

  private

16
  # rubocop:disable Gitlab/ModuleWithInstanceVariables
17
  def set_issuables_index
18
    @issuables = issuables_collection
19

20
    set_pagination
21
    return if redirect_out_of_range(@total_pages)
22

23
    if params[:label_name].present? && @project
24
25
      labels_params = { project_id: @project.id, title: params[:label_name] }
      @labels = LabelsFinder.new(current_user, labels_params).execute
26
27
28
    end

    @users = []
29
30
31
32
    if params[:assignee_id].present?
      assignee = User.find_by_id(params[:assignee_id])
      @users.push(assignee) if assignee
    end
33

34
35
36
37
    if params[:author_id].present?
      author = User.find_by_id(params[:author_id])
      @users.push(author) if author
    end
38
  end
39
40
41
42
43

  def set_pagination
    return if pagination_disabled?

    @issuables          = @issuables.page(params[:page])
44
    @issuables          = per_page_for_relative_position if params[:sort] == 'relative_position'
45
    @issuable_meta_data = issuable_meta_data(@issuables, collection_type, current_user)
46
47
    @total_pages        = issuable_page_count
  end
48
  # rubocop:enable Gitlab/ModuleWithInstanceVariables
49

50
51
52
53
  def pagination_disabled?
    false
  end

54
  # rubocop: disable CodeReuse/ActiveRecord
55
56
  def issuables_collection
    finder.execute.preload(preload_for_collection)
57
  end
58
  # rubocop: enable CodeReuse/ActiveRecord
59

60
  def redirect_out_of_range(total_pages)
61
    return false if total_pages.nil? || total_pages.zero?
62

63
    out_of_range = @issuables.current_page > total_pages # rubocop:disable Gitlab/ModuleWithInstanceVariables
64
65

    if out_of_range
66
      redirect_to(url_for(safe_params.merge(page: total_pages, only_path: true)))
67
68
69
70
71
    end

    out_of_range
  end

72
  def issuable_page_count
73
    page_count_for_relation(@issuables, finder.row_count) # rubocop:disable Gitlab/ModuleWithInstanceVariables
74
75
76
77
78
79
80
81
82
83
  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

84
85
86
87
88
  # 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

89
  def issuable_finder_for(finder_class)
90
    finder_class.new(current_user, finder_options)
91
92
  end

93
  # rubocop:disable Gitlab/ModuleWithInstanceVariables
94
95
  def finder_options
    params[:state] = default_state if params[:state].blank?
96

97
98
99
    options = {
      scope: params[:scope],
      state: params[:state],
100
      confidential: Gitlab::Utils.to_boolean(params[:confidential]),
101
      sort: set_sort_order
102
    }
103

104
105
    # Used by view to highlight active option
    @sort = options[:sort]
106

Riccardo Padovani's avatar
Riccardo Padovani committed
107
108
109
110
111
112
    # 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

113
    if @project
114
      options[:project_id] = @project.id
115
      options[:attempt_project_search_optimizations] = true
116
    elsif @group
117
118
      options[:group_id] = @group.id
      options[:include_subgroups] = true
119
      options[:attempt_group_search_optimizations] = true
120
121
    end

122
    params.permit(finder_type.valid_params).merge(options)
123
  end
124
  # rubocop:enable Gitlab/ModuleWithInstanceVariables
125

126
127
  def default_state
    'opened'
128
129
  end

George Koltsov's avatar
George Koltsov committed
130
131
  def legacy_sort_cookie_name
    'issuable_sort'
132
133
134
135
  end

  def default_sort_order
    case params[:state]
136
    when 'opened', 'all'    then sort_value_created_date
137
    when 'merged', 'closed' then sort_value_recently_updated
138
139
140
    else sort_value_created_date
    end
  end
141
142

  def finder
143
    @finder ||= issuable_finder_for(finder_type)
144
145
146
  end

  def collection_type
147
    @collection_type ||= if finder_type <= IssuesFinder
148
                           'Issue'
149
                         elsif finder_type <= MergeRequestsFinder
150
151
152
153
                           'MergeRequest'
                         end
  end

154
  # rubocop:disable Gitlab/ModuleWithInstanceVariables
155
  def preload_for_collection
156
    common_attributes = [:author, :assignees, :labels, :milestone]
157
158
    @preload_for_collection ||= case collection_type
                                when 'Issue'
159
                                  common_attributes + [:project, project: :namespace]
160
                                when 'MergeRequest'
161
                                  common_attributes + [:target_project, source_project: :route, head_pipeline: :project, target_project: :namespace, latest_merge_request_diff: :merge_request_diff_commits]
162
163
                                end
  end
164
  # rubocop:enable Gitlab/ModuleWithInstanceVariables
165
end