summaryrefslogtreecommitdiff
path: root/app/helpers/form_helper.rb
blob: a4d90716129d90c8ea1b4e0752cd9b39f6d37d6f (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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# frozen_string_literal: true

module FormHelper
  def form_errors(model, type: 'form', truncate: [], custom_message: [])
    errors = model.errors

    return unless errors.any?

    headline = n_(
      'The %{type} contains the following error:',
      'The %{type} contains the following errors:',
      errors.count
    ) % { type: type }

    truncate = Array.wrap(truncate)

    messages = errors.map do |error|
      attribute = error.attribute

      message = errors.full_message(attribute, error.message)

      # When error message is custom and does not follow the default pattern
      # "<attribute name> <error message>" (e.g. "You have already reported this
      # user"), use the message as-is
      message = error.message if custom_message.include?(attribute)

      message = html_escape_once(message).html_safe
      message = tag.span(message, class: 'str-truncated-100') if truncate.include?(attribute)
      message = append_help_page_link(message, error.options) if error.options[:help_page_url].present?

      tag.li(message)
    end.join.html_safe

    render Pajamas::AlertComponent.new(
      variant: :danger,
      title: headline,
      dismissible: false,
      alert_options: { id: 'error_explanation', class: 'gl-mb-5' }
    ) do |c|
      c.body do
        tag.ul(class: 'gl-pl-5 gl-mb-0') do
          messages
        end
      end
    end
  end

  def dropdown_max_select(data)
    if data[:'max-select'] && data[:'max-select'] < ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
      data[:'max-select']
    else
      ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
    end
  end

  def assignees_dropdown_options(issuable_type)
    dropdown_data = {
      toggle_class: 'js-user-search js-assignee-search js-multiselect js-save-user-data',
      title: _('Select assignee'),
      filter: true,
      dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee',
      placeholder: _('Search users'),
      data: {
        first_user: current_user&.username,
        null_user: true,
        current_user: true,
        project_id: (@target_project || @project)&.id,
        field_name: "#{issuable_type}[assignee_ids][]",
        default_label: _('Unassigned'),
        'max-select': 1,
        'dropdown-header': s_('SearchToken|Assignee'),
        multi_select: true,
        'input-meta': 'name',
        'always-show-selectbox': true,
        current_user_info: UserSerializer.new.represent(current_user)
      }
    }

    type = issuable_type.to_s

    if type == 'issue' && issue_supports_multiple_assignees? ||
        type == 'merge_request' && merge_request_supports_multiple_assignees?
      dropdown_data = multiple_assignees_dropdown_options(dropdown_data)
    end

    dropdown_data
  end

  def reviewers_dropdown_options(issuable_type, iid = nil, target_branch = nil)
    dropdown_data = {
      toggle_class: 'js-reviewer-search js-multiselect js-save-user-data',
      title: 'Request review from',
      filter: true,
      dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-reviewer',
      placeholder: _('Search users'),
      data: {
        first_user: current_user&.username,
        null_user: true,
        current_user: true,
        project_id: (@target_project || @project)&.id,
        field_name: "#{issuable_type}[reviewer_ids][]",
        default_label: 'Unassigned',
        'max-select': 1,
        'dropdown-header': 'Reviewer',
        multi_select: true,
        'input-meta': 'name',
        'always-show-selectbox': true,
        current_user_info: UserSerializer.new.represent(current_user)
      }
    }

    if iid
      dropdown_data[:data][:iid] = iid
    end

    if target_branch
      dropdown_data[:data][:target_branch] = target_branch
    end

    if merge_request_supports_multiple_reviewers?
      dropdown_data = multiple_reviewers_dropdown_options(dropdown_data)
    end

    dropdown_data[:data].merge!(reviewers_dropdown_options_for_suggested_reviewers)
    dropdown_data
  end

  # Overwritten
  def reviewers_dropdown_options_for_suggested_reviewers
    {}
  end

  # Overwritten
  def issue_supports_multiple_assignees?
    false
  end

  # Overwritten
  def merge_request_supports_multiple_assignees?
    false
  end

  # Overwritten
  def merge_request_supports_multiple_reviewers?
    false
  end

  private

  def append_help_page_link(message, options)
    help_page_url = options[:help_page_url]
    help_link_text = options[:help_link_text] || _('Learn more.')

    help_link = link_to(
      help_link_text,
      help_page_url,
      target: '_blank',
      rel: 'noopener noreferrer'
    )

    message + " #{help_link}".html_safe
  end

  def multiple_assignees_dropdown_options(options)
    new_options = options.dup

    new_options[:title] = _('Select assignee(s)')
    new_options[:data][:'dropdown-header'] = 'Assignee(s)'
    new_options[:data][:'max-select'] = ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS

    new_options
  end

  def multiple_reviewers_dropdown_options(options)
    new_options = options.dup

    new_options[:title] = _('Select reviewer(s)')
    new_options[:data][:'dropdown-header'] = _('Reviewer(s)')

    new_options[:data][:'max-select'] = ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS

    new_options
  end
end

FormHelper.prepend_mod_with('FormHelper')