Skip to content

Commit

Permalink
Add new section type: numeric field
Browse files Browse the repository at this point in the history
  • Loading branch information
Yalaeddin committed Apr 17, 2024
1 parent e20380c commit a0e5ea4
Show file tree
Hide file tree
Showing 12 changed files with 310 additions and 12 deletions.
22 changes: 22 additions & 0 deletions app/helpers/issue_templates_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,26 @@ def link_to_issue_template(template)
end
end

def numeric_edit_tag(tag_id, tag_name, value, min_value, max_value, options = {})
# Generate the range field tag with specified options
edit_tag = range_field_tag(tag_name,
value,
options.merge(id:tag_id,
min: min_value,
max: max_value
))

edit_tag << content_tag(:span, value, class: "range_selected_value")
# Add JavaScript to update the displayed value
edit_tag << javascript_tag(
<<~JAVASCRIPT
$(document).on("input change", "##{tag_id}", function(e) {
var value = $(this).val();
$(this).next('.range_selected_value').html(value);
})
JAVASCRIPT
)
edit_tag
end

end
54 changes: 53 additions & 1 deletion app/models/issue_template_section.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ def section_basic_entry(value, textile: true)
end
end

# validate_numeric_value method
#
# Validates whether a given value is numeric.
#
# Parameters:
# - field: The name of the field being validated.
# - value: The value to be validated.
# - errors: An optional object representing validation errors. If provided, errors will be added to it.
def validate_numerci_value(field, value, errors)
unless /^[+-]?\d+$/.match?(value.to_s.strip)
# Add an error if the value is not numeric
errors.add(field, ::I18n.t('activerecord.errors.messages.not_a_number')) unless errors.nil? || field.nil?
# Return false as validation failed
return false
end
# Return true as validation succeeded
return true
end
end

class IssueTemplateSectionTextField < IssueTemplateSection
Expand All @@ -64,7 +82,6 @@ def rendered_value(section_attributes, textile: true, value_only: false)
else
section_title(title, value, textile: textile)
end

end
end

Expand All @@ -85,6 +102,41 @@ def rendered_value(section_attributes, textile: true, value_only: false)
end
end

class IssueTemplateSectionNumeric < IssueTemplateSection
validates_presence_of :title
before_validation :validate_single_value
# Accessor for the integer_field attribute
# Used for custom error message in case of validation failure
attr_accessor :integer_field, :default_value_integer

def validate_single_value
# Call the method to validate if the value is numeric
if !empty_value.empty? && validate_numerci_value(:default_value_integer, empty_value, errors)
value = empty_value.to_i
if value < min_value
errors.add(:integer_field, ::I18n.t('activerecord.errors.messages.greater_than_or_equal_to', :count => min_value))
end
if value > max_value
errors.add(:integer_field, ::I18n.t('activerecord.errors.messages.less_than_or_equal_to', :count => max_value))
end
end
errors
end

def self.short_name
"numeric"
end

def rendered_value(section_attributes, textile: true, value_only: false)
value = value_from_text_attribute(section_attributes)
if value_only
section_basic_entry(value, textile: textile)
else
section_title(title, value, textile: textile)
end
end
end

class IssueTemplateSectionTextArea < IssueTemplateSection
validates_presence_of :title

Expand Down
12 changes: 4 additions & 8 deletions app/views/issue_templates/sections/_group_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,12 @@
<% end %>

</div>


<% locale = I18n.locale || I18n.default_locale %>
<% options = I18n.t('new_section_options', locale: locale) %>
<p data-target="split-description.add_buttons">
<%= select_tag 'new_section',
options_for_select([['Nouvelle consigne', 2],
['Nouveau champ texte (long)', 1],
['Nouveau champ texte (court)', 3],
['Nouvelle checkbox', 4],
['Nouveau champ date', 5],
['Nouvelle liste de valeurs', 7]
]),
options_for_select(options),
data: { target: "split-description.select_new_section_type" },
class: "select_new_section_type"
%>
Expand Down
25 changes: 25 additions & 0 deletions app/views/issue_templates/sections/_numeric_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<%= issue_template_section_form(form, IssueTemplateSectionNumeric, template) do %>
<p>
<%= form.text_field :title, :placeholder => :field_title, :label => :label_numeric, :size => 45, :required => true %>
</p>
<div class="collapsible">
<%= render partial: "issue_templates/sections/section_id", locals: {section: form.object} %>
<p>
<%= form.text_field :description, :placeholder => "Description", label: "Description", :size => 80 %>
</p>
<p>
<label for="custom_field_min_range"><%=l(:label_min_max_range)%></label>
<%= form.text_field :min_value, :size => 5, :no_label => true, pattern: '[-+]?\d*' %> -
<%= form.text_field :max_value, :size => 5, :no_label => true, pattern: '[-+]?\d*' %>
</p>
<p>
<%= form.text_field :empty_value, :label => :field_default_value, pattern: '[-+]?\d*' %>
</p>
<p>
<%= form.check_box :select_type, :label => :label_display_in_range %>
</p>
<p>
<%= form.check_box :required, :label => :label_field_required %>
</p>
</div>
<% end %>
32 changes: 32 additions & 0 deletions app/views/issues/sections/_numeric_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<p>
<%= label_tag do %>
<%= section.title %>
<% if section.required %>
<span class="required"> *</span>
<% end %>
<% if section.description.present? %>
<em class="info" style="padding-top: 3px; line-height: 1.5em;">
<%= section.description %>
</em>
<% end %>
<% end %>
<% value = reload_current_value(@sections_attributes, section, group_index) || section.empty_value %>
<% if section.select_type =="1" %>
<% section_group = section.issue_template_section_group %>
<% field_id = "issue_issue_template_section_groups_attributes_#{section_group.id}_#{group_index}_sections_attributes_#{section.id}_empty_value" %>
<% field_name = "issue[issue_template][section_groups_attributes][#{section_group.id}][#{group_index}][sections_attributes][#{section.id}][empty_value]" %>
<%= numeric_edit_tag field_id, field_name, section.empty_value, section.min_value, section.max_value %>
<% else %>
<% min_value = section.min_value || 0 %>
<% max_value = section.max_value || 100 %>
<%= form.number_field :empty_value,
size: 20,
accesskey: accesskey(:edit),
no_label: true,
required: section.required,
value: value,
min: min_value,
max: max_value
%>
<% end %>
</p>
3 changes: 3 additions & 0 deletions assets/javascripts/issue_templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ function makeListsSortable() {
case('5'):
template = sectionGroupElement.querySelector(".split_description.template.date").outerHTML
break
case('6'):
template = sectionGroupElement.querySelector(".split_description.template.numeric").outerHTML
break
case('7'):
template = sectionGroupElement.querySelector(".split_description.template.select").outerHTML
break
Expand Down
16 changes: 14 additions & 2 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,20 @@ en:
delete_repeatable_bloc_label: Custom text for block delete button (optional)
field_assignable_projects: "Template projects"
show_in_generated_issue: Show in the generated issue
label_icon: Icon
label_numeric: Numeric
label_display_in_range: Range display
field_integer_field: "La valeur du champ entier"
new_section_options:
- ['New Instruction', 2]
- ['New Long Text Field', 1]
- ['New Short Text Field', 3]
- ['New Checkbox', 4]
- ['New Date Field', 5]
- ['New Numeric Field', 6]
- ['New Value List', 7]
label_field_required: Required field
label_icon: Icon
icon_name_placeholder: "Octicon name"
field_buttons_with_icons_field: Buttons with icons
label_value_at_index: "%{title} : value at index %{key} is empty"
label_copy: Copy of
label_copy: Copy of
15 changes: 14 additions & 1 deletion config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,21 @@ fr:
delete_repeatable_bloc_label: Texte personnalisé pour le bouton de suppression du bloc (facultatif)
field_assignable_projects: "Projets"
show_in_generated_issue: Afficher dans la demande générée
label_numeric: Entier
label_display_in_range: Affichage en range
field_integer_field: La valeur du champ entier
field_default_value_integer: La valeur par défaut du champ entier
new_section_options:
- ['Nouvelle consigne', 2]
- ['Nouveau champ texte (long)', 1]
- ['Nouveau champ texte (court)', 3]
- ['Nouvelle checkbox', 4]
- ['Nouveau champ date', 5]
- ['Nouvelle champ entier', 6]
- ['Nouvelle liste de valeurs', 7]
label_field_required: Champ obligatoire
label_icon: Icone
icon_name_placeholder: "Nom de l'octicon"
field_buttons_with_icons_field: Boutons avec icones
label_value_at_index: "%{title} : la valeur à l'indice %{key} est vide"
label_copy: Copie de
label_copy: Copie de
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddMaxMinValueToTemplateSections < ActiveRecord::Migration[5.2]
def change
add_column :issue_template_sections, :min_value, :integer
add_column :issue_template_sections, :max_value, :integer
end
end
96 changes: 96 additions & 0 deletions spec/controllers/issue_templates_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,102 @@
expect(IssueTemplate.last.section_groups.first.sections.first.text).to eq("value1;value2")
expect(IssueTemplate.last.section_groups.first.sections.first.icon_name).to eq("history;alert-fill")
end

it "Should successfully creates issue template section with range" do
expect do
post :create, params: {
:issue_template => {
:template_title => "New template",
:template_enabled => "1",
:template_project_ids => ["1"],
:tracker_id => 1,
:status_id => 1,
section_groups_attributes: [
{ "position" => "1",
"title" => "test",
"repeatable" => "0",
sections_attributes: [
{ "position" => "1",
"title" => "test range",
"type" => "IssueTemplateSectionNumeric",
"min_value" => 2,
"max_value" => 4,
"empty_value" => 3,
"select_type" => "0" #display_in_range
},
]
}
]
}
}
end.to change { IssueTemplate.count }.by(1)

new_template = IssueTemplate.last.section_groups.first.sections.first
expect(new_template.min_value).to eq(2)
expect(new_template.max_value).to eq(4)
expect(new_template.empty_value).to eq("3")
expect(new_template.select_type).to eq("0")
end

it "Should not accept a default value longer than the maximum specified" do
expect do
post :create, params: {
:issue_template => {
:template_title => "New template",
:template_enabled => "1",
:template_project_ids => ["1"],
:tracker_id => 1,
:status_id => 1,
section_groups_attributes: [
{ "position" => "1",
"title" => "test",
"repeatable" => "0",
sections_attributes: [
{ "position" => "1",
"title" => "test range",
"type" => "IssueTemplateSectionNumeric",
"min_value" => 1,
"max_value" => 2,
"empty_value" => 5,
"select_type" => "0" #display_in_range
},
]
}
]
}
}
end.to change { IssueTemplate.count }.by(0)
end

it "Should not accept a default value shorter than the minimum specified length" do
expect do
post :create, params: {
:issue_template => {
:template_title => "New template",
:template_enabled => "1",
:template_project_ids => ["1"],
:tracker_id => 1,
:status_id => 1,
section_groups_attributes: [
{ "position" => "1",
"title" => "test",
"repeatable" => "0",
sections_attributes: [
{ "position" => "1",
"title" => "test range",
"type" => "IssueTemplateSectionNumeric",
"min_value" => 2,
"max_value" => 4,
"empty_value" => 5,
"select_type" => "0" #display_in_range
},
]
}
]
}
}
end.to change { IssueTemplate.count }.by(0)
end
end

describe "issue creation" do
Expand Down
10 changes: 10 additions & 0 deletions spec/fixtures/issue_template_sections.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,13 @@ repeatable_select_with_radio:
position: 9
required: true
select_type: "radio"
field_numeric_as_range:
id: 21
title: "Numeric Field as range"
type: "IssueTemplateSectionNumeric"
max_value: 8
min_value: 1
empty_value: "5"
issue_template_section_group_id: 5
position: 10
select_type: "0"
Loading

0 comments on commit a0e5ea4

Please sign in to comment.