<%= f.text_field :name, required: true, size: 25 %>
5 |<%= group_fields_edit_tag @custom_fields_group %> 6 |
6 | <%= submit_tag l :button_save %> 7 |
8 | <% end %> 9 | -------------------------------------------------------------------------------- /app/views/custom_fields_groups/index.html.erb: -------------------------------------------------------------------------------- 1 |<%= l(:field_name) %> | 12 |<%= l(:label_custom_field_plural) %> | 13 |14 | |
---|
<%= l :label_no_data %>
23 | <% end %> 24 | 25 | <%= javascript_tag do %> 26 | $(function() { $("table.custom_fields_groups tbody").positionedItems(); }); 27 | <% end %> 28 | -------------------------------------------------------------------------------- /app/views/custom_fields_groups/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= title [l(:label_custom_fields_group_plural), custom_fields_groups_path], l(:label_custom_fields_group_new) %> 2 | 3 | <%= labelled_form_for :custom_fields_group, @custom_fields_group, url: custom_fields_groups_path do |f| %> 4 | <%= render partial: 'form', locals: { f: f } %> 5 |6 | <%= submit_tag l :button_create %> 7 | <%= submit_tag l(:button_create_and_continue), name: 'continue' %> 8 |
9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/issues/_form_custom_fields.html.erb: -------------------------------------------------------------------------------- 1 | <% custom_fields_group_tag = User.current.pref.custom_fields_group_tag %> 2 | <% if custom_fields_group_tag.blank? %> 3 | <% custom_fields_group_tag = Setting.plugin_redmine_custom_fields_groups['custom_fields_group_tag'] || 'h4' %> 4 | <% end %> 5 | <% fieldset_default_state = User.current.pref.fieldset_default_state %> 6 | <% if fieldset_default_state.blank? %> 7 | <% fieldset_default_state = Setting.plugin_redmine_custom_fields_groups['fieldset_default_state'] || 'all_expended' %> 8 | <% end %> 9 | <% all_collapsed = (fieldset_default_state == 'all_collapsed') %> 10 | <% grouped_custom_field_values(@issue.editable_custom_field_values).each do |title, values| %> 11 | <% if values.present? %> 12 | <% full_width_values = values.select { |value| value.custom_field.full_width_layout? } %> 13 | <% half_width_values = values - full_width_values %> 14 | <% if custom_fields_group_tag == 'fieldset' %> 15 | <% if title.nil? %> 16 | <% if half_width_values.present? %> 17 |<%= custom_field_tag_with_label :issue, value, :required => @issue.required_attribute?(value.custom_field_id) %>
23 | <% if i == split_on -%> 24 |<%= custom_field_tag_with_label :issue, value, :required => @issue.required_attribute?(value.custom_field_id) %>
34 | <%= wikitoolbar_for "issue_custom_field_values_#{value.custom_field_id}", preview_issue_path(:project_id => @issue.project, :issue_id => @issue.id) if value.custom_field.full_text_formatting? %> 35 | <% end %> 36 | <% else %> 37 | <% fieldset_class = 'collapsible custom-fields-groups' + (all_collapsed ? ' collapsed' : '') %> 38 | <% legend_class = 'icon icon-' + (all_collapsed ? 'collapsed' : ((Redmine::VERSION.to_s >= '5.0.0') ? 'expanded' : 'expended')) %> 39 | <% div_style = all_collapsed ? 'display: none' : '' %> 40 | 63 | <% end %> 64 | <% else %> 65 | <%= content_tag(custom_fields_group_tag, title, :class => "custom-fields-groups") unless title.nil? %> 66 | <% if half_width_values.present? %> 67 |<%= custom_field_tag_with_label :issue, value, :required => @issue.required_attribute?(value.custom_field_id) %>
73 | <% if i == split_on -%> 74 |<%= custom_field_tag_with_label :issue, value, :required => @issue.required_attribute?(value.custom_field_id) %>
84 | <%= wikitoolbar_for "issue_custom_field_values_#{value.custom_field_id}", preview_issue_path(:project_id => @issue.project, :issue_id => @issue.id) if value.custom_field.full_text_formatting? %> 85 | <% end %> 86 | <% end %> 87 | <% end %> 88 | <% end %> 89 | -------------------------------------------------------------------------------- /app/views/settings/_redmine_custom_fields_groups.html.erb: -------------------------------------------------------------------------------- 1 |4 | <%= content_tag(:label, l(:label_custom_fields_group_tag)) %> 5 | <%= select_tag('settings[custom_fields_group_tag]', 6 | options_for_select( 7 | RedmineCustomFieldsGroups::Options::group_tags, 8 | @settings['custom_fields_group_tag'].to_s)) %> 9 |
10 |11 | <%= content_tag(:label, l(:label_fieldset_default_state)) %> 12 | <%= select_tag('settings[fieldset_default_state]', 13 | options_for_select( 14 | RedmineCustomFieldsGroups::Options::fieldset_states, 15 | @settings['fieldset_default_state'].to_s)) %> 16 |
17 |" 18 | s << label_tag("pref_custom_fields_group_tag", l(:label_custom_fields_group_tag)) 19 | s << select_tag( 20 | "pref[custom_fields_group_tag]", 21 | options_for_select([["",""]] + RedmineCustomFieldsGroups::Options::group_tags, user.pref.custom_fields_group_tag), 22 | :id => 'pref_custom_fields_group_tag', 23 | :blank => '' 24 | ) 25 | s << "
" 26 | s << "" 27 | s << label_tag("pref_fieldset_default_state", l(:label_fieldset_default_state)) 28 | s << select_tag( 29 | "pref[fieldset_default_state]", 30 | options_for_select([["",""]] + RedmineCustomFieldsGroups::Options::fieldset_states, user.pref.fieldset_default_state), 31 | :id => 'pref_fieldset_default_state', 32 | :blank => '' 33 | ) 34 | s << "
" 35 | 36 | return s.html_safe 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/redmine_custom_fields_groups/options.rb: -------------------------------------------------------------------------------- 1 | module RedmineCustomFieldsGroups 2 | class Options 3 | include Redmine::I18n 4 | def self.group_tags 5 | [ 6 | [l(:label_group_tag_h3), "h3"], 7 | [l(:label_group_tag_h4), "h4"], 8 | [l(:label_group_tag_fieldset), "fieldset"] 9 | ] 10 | end 11 | def self.fieldset_states 12 | [ 13 | [l(:label_fieldset_state_all_expended), "all_expended"], 14 | [l(:label_fieldset_state_all_collapsed), "all_collapsed"], 15 | ] 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/redmine_custom_fields_groups/patches/issues_helper_patch.rb: -------------------------------------------------------------------------------- 1 | module RedmineCustomFieldsGroups 2 | module Patches 3 | module IssuesHelperPatch 4 | 5 | def self.included(base) 6 | base.extend(ClassMethods) 7 | base.send(:prepend, InstanceMethods) 8 | base.class_eval do 9 | 10 | # Referred: 11 | # - Patch #30919: Group Issues Custom Fields - (Form like Issues) - Redmine 12 | # - https://www.redmine.org/issues/30919 13 | def grouped_custom_field_values(custom_field_values) 14 | keys_grouped = CustomFieldsGroupField. 15 | joins(:custom_fields_group, :custom_field). 16 | order('custom_fields_groups.position', 'custom_fields.position'). 17 | pluck('custom_fields_groups.name', :custom_field_id).group_by(&:shift) 18 | custom_fields_grouped = { nil => (keys_grouped[nil].nil? ? [] : 19 | keys_grouped[nil].map{|n| custom_field_values.select{|x| x.custom_field[:id] == n[0]}}.flatten) | 20 | custom_field_values.select{|y| ! keys_grouped.values.flatten.include?(y.custom_field[:id])}} 21 | keys_grouped.reject{|k,v| k == nil}.each{|k,v| custom_fields_grouped[k] = 22 | v.map{|n| custom_field_values.select{|x| x.custom_field[:id] == n[0]}}.flatten} 23 | custom_fields_grouped 24 | end 25 | 26 | def render_custom_fields_rows_by_groups(issue) 27 | custom_field_values = issue.visible_custom_field_values 28 | return if custom_field_values.empty? 29 | 30 | custom_fields_group_tag = User.current.pref.custom_fields_group_tag 31 | if custom_fields_group_tag.blank? 32 | custom_fields_group_tag = Setting.plugin_redmine_custom_fields_groups['custom_fields_group_tag'] || 'h4' 33 | end 34 | fieldset_default_state = User.current.pref.fieldset_default_state 35 | if fieldset_default_state.blank? 36 | fieldset_default_state = Setting.plugin_redmine_custom_fields_groups['fieldset_default_state'] || 'all_expended' 37 | end 38 | 39 | s = ''.html_safe 40 | grouped_custom_field_values(custom_field_values).each do |title, values| 41 | if values.present? 42 | if custom_fields_group_tag == 'fieldset' 43 | if title.nil? 44 | s << render_half_width_custom_fields_rows_by_grouped_values(issue, values) 45 | s << render_full_width_custom_fields_rows_by_grouped_values(issue, values) 46 | else 47 | s << content_tag('fieldset', :class => 'collapsible custom-fields-groups') do 48 | concat content_tag('legend', title, :onclick => 'toggleFieldset(this);', 49 | :class => 'icon icon-' + ((Redmine::VERSION.to_s >= '5.0.0') ? 'expanded' : 'expended')) 50 | concat render_half_width_custom_fields_rows_by_grouped_values(issue, values) 51 | concat render_full_width_custom_fields_rows_by_grouped_values(issue, values) 52 | end 53 | end 54 | else 55 | s << content_tag(custom_fields_group_tag, title, :class => 'custom-fields-groups') unless title.nil? 56 | s << render_half_width_custom_fields_rows_by_grouped_values(issue, values) 57 | s << render_full_width_custom_fields_rows_by_grouped_values(issue, values) 58 | end 59 | end 60 | end 61 | # temporary hack 62 | if custom_fields_group_tag == 'fieldset' && fieldset_default_state == 'all_collapsed' 63 | s << javascript_tag("$('div.issue div.attributes fieldset.custom-fields-groups>legend').each(function(idx,elem){toggleFieldset(elem);})") 64 | end 65 | s 66 | end 67 | 68 | def render_half_width_custom_fields_rows_by_grouped_values(issue, custom_field_values) 69 | values = custom_field_values.reject {|value| value.custom_field.full_width_layout?} 70 | return if values.empty? 71 | 72 | half = (values.size / 2.0).ceil 73 | issue_fields_rows do |rows| 74 | values.each_with_index do |value, i| 75 | m = (i < half ? :left : :right) 76 | rows.send m, custom_field_name_tag(value.custom_field), custom_field_value_tag(value), :class => value.custom_field.css_classes 77 | end 78 | end 79 | end 80 | 81 | def render_full_width_custom_fields_rows_by_grouped_values(issue, custom_field_values) 82 | values = custom_field_values.select {|value| value.custom_field.full_width_layout?} 83 | return if values.empty? 84 | 85 | s = ''.html_safe 86 | values.each_with_index do |value, i| 87 | # attr_value_tag = custom_field_value_tag(value) 88 | # next if attr_value_tag.blank? 89 | 90 | # content = 91 | # content_tag('hr') + 92 | # content_tag('p', content_tag('strong', custom_field_name_tag(value.custom_field) )) + 93 | # content_tag('div', attr_value_tag, class: 'value') 94 | # s << content_tag('div', content, class: "#{value.custom_field.css_classes} attribute") 95 | content = content_tag('div', custom_field_name_tag(value.custom_field) + ":", :class => 'label') + 96 | content_tag('div', custom_field_value_tag(value), :class => 'value') 97 | content = content_tag('div', content, :class => "#{value.custom_field.css_classes} attribute") 98 | s << content_tag('div', content, :class => 'splitcontent') 99 | end 100 | s 101 | end 102 | end #base 103 | end #self 104 | 105 | module InstanceMethods 106 | 107 | end #module 108 | 109 | module ClassMethods 110 | 111 | end #module 112 | end #module 113 | end #module 114 | end #module 115 | -------------------------------------------------------------------------------- /lib/redmine_custom_fields_groups/patches/user_preference_patch.rb: -------------------------------------------------------------------------------- 1 | module RedmineCustomFieldsGroups 2 | module Patches 3 | module UserPreferencePatch 4 | 5 | def self.included(base) # :nodoc: 6 | base.send(:include, InstanceMethods) 7 | 8 | base.class_eval do 9 | safe_attributes 'custom_fields_group_tag', 'fieldset_default_state' 10 | end 11 | end 12 | 13 | module InstanceMethods 14 | def custom_fields_group_tag 15 | self[:custom_fields_group_tag] 16 | end 17 | 18 | def custom_fields_group_tag=(new_value) 19 | self[:custom_fields_group_tag] = new_value 20 | end 21 | 22 | def fieldset_default_state 23 | self[:fieldset_default_state] 24 | end 25 | 26 | def fieldset_default_state=(new_value) 27 | self[:fieldset_default_state] = new_value 28 | end 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /test/fixtures/custom_fields_group_fields.yml: -------------------------------------------------------------------------------- 1 | custom_fields_group_fields_101: 2 | custom_fields_group_id: 1 3 | custom_field_id: 1 4 | custom_fields_group_fields_102: 5 | custom_fields_group_id: 1 6 | custom_field_id: 2 7 | custom_fields_group_fields_206: 8 | custom_fields_group_id: 2 9 | custom_field_id: 6 10 | custom_fields_group_fields_308: 11 | custom_fields_group_id: 3 12 | custom_field_id: 8 13 | -------------------------------------------------------------------------------- /test/fixtures/custom_fields_groups.yml: -------------------------------------------------------------------------------- 1 | custom_fields_groups_100: 2 | id: 1 3 | name: Group 1 4 | position: 1 5 | custom_fields_groups_200: 6 | id: 2 7 | name: Group 2 8 | position: 2 9 | custom_fields_groups_300: 10 | id: 3 11 | name: Group 3 12 | position: 3 13 | -------------------------------------------------------------------------------- /test/functional/custom_fields_groups_controller_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../test_helper' 2 | 3 | class CustomFieldsGroupsControllerTest < ActionController::TestCase 4 | fixtures :custom_fields, :custom_fields_groups, :custom_fields_group_fields, 5 | :users 6 | 7 | setup do 8 | User.current = nil 9 | @request.session[:user_id] = 1 # admin 10 | end 11 | 12 | teardown do 13 | @request.session.clear 14 | end 15 | 16 | test 'should require admin' do 17 | @request.session[:user_id] = nil 18 | get :index 19 | assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fcustom_fields_groups' 20 | end 21 | 22 | test 'should get index' do 23 | get :index 24 | assert_response :success 25 | 26 | assert_select 'table.custom_fields_groups tbody' do 27 | assert_select 'tr', CustomFieldsGroup.count 28 | assert_select 'a[href="/custom_fields_groups/1/edit"]', :text => 'Group 1' 29 | end 30 | end 31 | 32 | test 'should get new' do 33 | get :new 34 | assert_response :success 35 | assert_select 'input[type=text][name=?]', 'custom_fields_group[name]' 36 | assert_select 'input[type=checkbox][name=?][value=?]', 'custom_fields_group[custom_field_ids][]', '9' 37 | end 38 | 39 | test 'should create custom fields gruop' do 40 | assert_difference 'CustomFieldsGroup.count' do 41 | post :create, :params => { 42 | :custom_fields_group => { 43 | :name => 'Group 4', 44 | :custom_field_ids => [9] 45 | } 46 | } 47 | end 48 | assert_redirected_to '/custom_fields_groups' 49 | 50 | assert custom_fields_group = CustomFieldsGroup.find_by_name('Group 4') 51 | assert_equal [9], custom_fields_group.custom_field_ids 52 | assert_equal 4, custom_fields_group.position 53 | end 54 | 55 | test 'should not create custom fields gruop without name' do 56 | post :create, :params => { 57 | :custom_fields_group => { 58 | :name => '', 59 | :custom_field_ids => [9] 60 | } 61 | } 62 | assert_response :success 63 | assert_select_error /Name cannot be blank/ 64 | end 65 | 66 | test 'should get edit' do 67 | get :edit, :params => { :id => 1 } 68 | assert_response :success 69 | 70 | assert_select 'input[type=text][name=?][value=?]', 'custom_fields_group[name]', 'Group 1' 71 | assert_select 'input[type=checkbox][name=?][value=?][checked=?]', 'custom_fields_group[custom_field_ids][]', '1', 'checked' 72 | assert_select 'input[type=checkbox][name=?][value=?][checked=?]', 'custom_fields_group[custom_field_ids][]', '2', 'checked' 73 | end 74 | 75 | test 'should update custom fields group' do 76 | post :update, :params => { 77 | :id => 1, 78 | :custom_fields_group => { 79 | :name => 'Group 1 updated', 80 | :custom_field_ids => [2] 81 | } 82 | } 83 | assert_redirected_to '/custom_fields_groups' 84 | 85 | assert custom_fields_group = CustomFieldsGroup.find(1) 86 | assert_equal 'Group 1 updated', custom_fields_group.name 87 | assert_equal [2], custom_fields_group.custom_field_ids 88 | end 89 | 90 | test 'should not update custom fields group without name' do 91 | post :update, :params => { 92 | :id => 1, 93 | :custom_fields_group => { 94 | :name => '', 95 | :custom_field_ids => [2] 96 | } 97 | } 98 | assert_response :success 99 | assert_select_error /Name cannot be blank/ 100 | end 101 | 102 | test 'should destroy custom fields group' do 103 | assert_difference 'CustomFieldsGroup.count', -1 do 104 | delete :destroy, :params => { :id => 1 } 105 | end 106 | assert_redirected_to '/custom_fields_groups' 107 | end 108 | 109 | test 'move highest' do 110 | put :update, :params => { 111 | :id => 2, 112 | :custom_fields_group => { 113 | :position => 1 114 | } 115 | }, :xhr => true 116 | assert_response :success 117 | assert_equal 1, CustomFieldsGroup.find(2).position 118 | end 119 | 120 | test 'move higher' do 121 | position = CustomFieldsGroup.find(2).position 122 | put :update, :params => { 123 | :id => 2, 124 | :custom_fields_group => { 125 | :position => position - 1 126 | } 127 | }, :xhr => true 128 | assert_response :success 129 | assert_equal position - 1, CustomFieldsGroup.find(2).position 130 | end 131 | 132 | test 'move lower' do 133 | position = CustomFieldsGroup.find(2).position 134 | put :update, :params => { 135 | :id => 2, 136 | :custom_fields_group => { 137 | :position => position + 1 138 | } 139 | }, :xhr => true 140 | assert_response :success 141 | assert_equal position + 1, CustomFieldsGroup.find(2).position 142 | end 143 | 144 | test 'move lowest' do 145 | put :update, :params => { 146 | :id => 2, 147 | :custom_fields_group => { 148 | :position => CustomFieldsGroup.count 149 | } 150 | }, :xhr => true 151 | assert_response :success 152 | assert_equal CustomFieldsGroup.count, CustomFieldsGroup.find(2).position 153 | end 154 | end 155 | -------------------------------------------------------------------------------- /test/integration/layout_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../test_helper' 2 | 3 | class LayoutTest < Redmine::IntegrationTest 4 | fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles, 5 | :trackers, :projects_trackers, :enabled_modules, :issue_statuses, :issues, 6 | :enumerations, :custom_fields, :custom_values, :custom_fields_trackers, 7 | :watchers, :journals, :journal_details, :versions, 8 | :workflows, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, 9 | :custom_fields, :custom_fields_groups, :custom_fields_group_fields 10 | 11 | setup do 12 | User.current = nil 13 | @user = User.find_by_login('dlopper') 14 | end 15 | 16 | teardown do 17 | Setting.where(name: 'plugin_redmine_custom_fields_groups').destroy_all 18 | Setting.clear_cache 19 | @user.pref.others.delete(:custom_fields_group_tag) 20 | @user.pref.others.delete(:fieldset_default_state) 21 | end 22 | 23 | test 'should show custom fields groups with default h4 tag in issue' do 24 | log_user('dlopper', 'foo') 25 | get '/issues/1' 26 | assert_response :success 27 | 28 | # issue details 29 | assert_select 'div.issue.details div.attributes h4.custom-fields-groups:contains("Group 1") + div.splitcontent' do 30 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 31 | assert_select 'span', :text => 'Searchable field' 32 | assert_select 'div.value', :text => '125' 33 | end 34 | assert_select 'div.splitcontentleft:nth-of-type(2)' do 35 | assert_select 'span', :text => 'Database' 36 | assert_select 'div.value', :text => '' 37 | end 38 | end 39 | assert_select 'div.issue.details div.attributes h4.custom-fields-groups:contains("Group 2") + div.splitcontent' do 40 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 41 | assert_select 'span', :text => 'Float field' 42 | assert_select 'div.value', :text => '2.10' 43 | end 44 | end 45 | assert_select 'div.issue.details div.attributes h4.custom-fields-groups:contains("Group 3") + div.splitcontent' do 46 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 47 | assert_select 'span', :text => 'Custom date' 48 | assert_select 'div.value', :text => '12/01/2009' 49 | end 50 | end 51 | 52 | # issue edit 53 | assert_select 'div#update div.attributes h4.custom-fields-groups:contains("Group 1") + div.splitcontent' do 54 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 55 | assert_select 'span', :text => 'Searchable field' 56 | assert_select 'input[type=text][name=?]', 'issue[custom_field_values][2]', :value => '125' 57 | end 58 | assert_select 'div.splitcontentright:nth-of-type(1)' do 59 | assert_select 'span', :text => 'Database' 60 | assert_select 'select[name=?]', 'issue[custom_field_values][1]', :value => '' 61 | end 62 | end 63 | assert_select 'div#update div.attributes h4.custom-fields-groups:contains("Group 2") + div.splitcontent' do 64 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 65 | assert_select 'span', :text => 'Float field' 66 | assert_select 'input[type=text][name=?]', 'issue[custom_field_values][6]', :value => '2.1' 67 | end 68 | end 69 | assert_select 'div#update div.attributes h4.custom-fields-groups:contains("Group 3") + div.splitcontent' do 70 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 71 | assert_select 'span', :text => 'Custom date' 72 | assert_select 'input[type=date][name=?]', 'issue[custom_field_values][8]', :value => '2009-12-01' 73 | end 74 | end 75 | end 76 | 77 | test 'should show custom fields groups with h3 tag in issue from plugin setting' do 78 | Setting.plugin_redmine_custom_fields_groups = { 'custom_fields_group_tag' => 'h3' } 79 | 80 | log_user('dlopper', 'foo') 81 | get '/issues/1' 82 | assert_response :success 83 | 84 | # issue details 85 | assert_select 'div.issue.details div.attributes h3.custom-fields-groups:contains("Group 1") + div.splitcontent' do 86 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 87 | assert_select 'span', :text => 'Searchable field' 88 | assert_select 'div.value', :text => '125' 89 | end 90 | assert_select 'div.splitcontentleft:nth-of-type(2)' do 91 | assert_select 'span', :text => 'Database' 92 | assert_select 'div.value', :text => '' 93 | end 94 | end 95 | assert_select 'div.issue.details div.attributes h3.custom-fields-groups:contains("Group 2") + div.splitcontent' do 96 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 97 | assert_select 'span', :text => 'Float field' 98 | assert_select 'div.value', :text => '2.10' 99 | end 100 | end 101 | assert_select 'div.issue.details div.attributes h3.custom-fields-groups:contains("Group 3") + div.splitcontent' do 102 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 103 | assert_select 'span', :text => 'Custom date' 104 | assert_select 'div.value', :text => '12/01/2009' 105 | end 106 | end 107 | 108 | # issue edit 109 | assert_select 'div#update div.attributes h3.custom-fields-groups:contains("Group 1") + div.splitcontent' do 110 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 111 | assert_select 'span', :text => 'Searchable field' 112 | assert_select 'input[type=text][name=?]', 'issue[custom_field_values][2]', :value => '125' 113 | end 114 | assert_select 'div.splitcontentright:nth-of-type(1)' do 115 | assert_select 'span', :text => 'Database' 116 | assert_select 'select[name=?]', 'issue[custom_field_values][1]', :value => '' 117 | end 118 | end 119 | assert_select 'div#update div.attributes h3.custom-fields-groups:contains("Group 2") + div.splitcontent' do 120 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 121 | assert_select 'span', :text => 'Float field' 122 | assert_select 'input[type=text][name=?]', 'issue[custom_field_values][6]', :value => '2.1' 123 | end 124 | end 125 | assert_select 'div#update div.attributes h3.custom-fields-groups:contains("Group 3") + div.splitcontent' do 126 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 127 | assert_select 'span', :text => 'Custom date' 128 | assert_select 'input[type=date][name=?]', 'issue[custom_field_values][8]', :value => '2009-12-01' 129 | end 130 | end 131 | end 132 | 133 | test 'should show custom fields groups with fieldset tag all expended in issue from plugin setting' do 134 | Setting.plugin_redmine_custom_fields_groups = { 135 | 'custom_fields_group_tag' => 'fieldset', 136 | 'fieldset_default_state' => 'all_expended' 137 | } 138 | 139 | log_user('dlopper', 'foo') 140 | get '/issues/1' 141 | assert_response :success 142 | 143 | # issue details 144 | assert_select 'div.issue.details div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 1") + div.splitcontent' do 145 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 146 | assert_select 'span', :text => 'Searchable field' 147 | assert_select 'div.value', :text => '125' 148 | end 149 | assert_select 'div.splitcontentleft:nth-of-type(2)' do 150 | assert_select 'span', :text => 'Database' 151 | assert_select 'div.value', :text => '' 152 | end 153 | end 154 | assert_select 'div.issue.details div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 2") + div.splitcontent' do 155 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 156 | assert_select 'span', :text => 'Float field' 157 | assert_select 'div.value', :text => '2.10' 158 | end 159 | end 160 | assert_select 'div.issue.details div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 3") + div.splitcontent' do 161 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 162 | assert_select 'span', :text => 'Custom date' 163 | assert_select 'div.value', :text => '12/01/2009' 164 | end 165 | end 166 | 167 | # issue edit 168 | assert_select 'div#update div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 1") + div.splitcontent' do 169 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 170 | assert_select 'span', :text => 'Searchable field' 171 | assert_select 'input[type=text][name=?]', 'issue[custom_field_values][2]', :value => '125' 172 | end 173 | assert_select 'div.splitcontentright:nth-of-type(1)' do 174 | assert_select 'span', :text => 'Database' 175 | assert_select 'select[name=?]', 'issue[custom_field_values][1]', :value => '' 176 | end 177 | end 178 | assert_select 'div#update div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 2") + div.splitcontent' do 179 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 180 | assert_select 'span', :text => 'Float field' 181 | assert_select 'input[type=text][name=?]', 'issue[custom_field_values][6]', :value => '2.1' 182 | end 183 | end 184 | assert_select 'div#update div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 3") + div.splitcontent' do 185 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 186 | assert_select 'span', :text => 'Custom date' 187 | assert_select 'input[type=date][name=?]', 'issue[custom_field_values][8]', :value => '2009-12-01' 188 | end 189 | end 190 | end 191 | 192 | test 'should override user preference setting than plugin setting' do 193 | Setting.plugin_redmine_custom_fields_groups = { 194 | 'custom_fields_group_tag' => 'h4', # default 195 | 'fieldset_default_state' => 'all_collapsed' 196 | } 197 | 198 | @user.pref.others[:custom_fields_group_tag] = 'fieldset' 199 | @user.pref.others[:fieldset_default_state] = 'all_expended' 200 | @user.pref.save! 201 | 202 | log_user('dlopper', 'foo') 203 | get '/issues/1' 204 | assert_response :success 205 | 206 | # issue details 207 | assert_select 'div.issue.details div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 1") + div.splitcontent' do 208 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 209 | assert_select 'span', :text => 'Searchable field' 210 | assert_select 'div.value', :text => '125' 211 | end 212 | assert_select 'div.splitcontentleft:nth-of-type(2)' do 213 | assert_select 'span', :text => 'Database' 214 | assert_select 'div.value', :text => '' 215 | end 216 | end 217 | assert_select 'div.issue.details div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 2") + div.splitcontent' do 218 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 219 | assert_select 'span', :text => 'Float field' 220 | assert_select 'div.value', :text => '2.10' 221 | end 222 | end 223 | assert_select 'div.issue.details div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 3") + div.splitcontent' do 224 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 225 | assert_select 'span', :text => 'Custom date' 226 | assert_select 'div.value', :text => '12/01/2009' 227 | end 228 | end 229 | 230 | # issue edit 231 | assert_select 'div#update div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 1") + div.splitcontent' do 232 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 233 | assert_select 'span', :text => 'Searchable field' 234 | assert_select 'input[type=text][name=?]', 'issue[custom_field_values][2]', :value => '125' 235 | end 236 | assert_select 'div.splitcontentright:nth-of-type(1)' do 237 | assert_select 'span', :text => 'Database' 238 | assert_select 'select[name=?]', 'issue[custom_field_values][1]', :value => '' 239 | end 240 | end 241 | assert_select 'div#update div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 2") + div.splitcontent' do 242 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 243 | assert_select 'span', :text => 'Float field' 244 | assert_select 'input[type=text][name=?]', 'issue[custom_field_values][6]', :value => '2.1' 245 | end 246 | end 247 | assert_select 'div#update div.attributes fieldset.custom-fields-groups > legend.icon:contains("Group 3") + div.splitcontent' do 248 | assert_select 'div.splitcontentleft:nth-of-type(1)' do 249 | assert_select 'span', :text => 'Custom date' 250 | assert_select 'input[type=date][name=?]', 'issue[custom_field_values][8]', :value => '2009-12-01' 251 | end 252 | end 253 | end 254 | end 255 | -------------------------------------------------------------------------------- /test/system/fieldset_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../../test/application_system_test_case' 2 | require_relative '../test_helper' 3 | 4 | class FieldsetTest < ApplicationSystemTestCase 5 | fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles, 6 | :trackers, :projects_trackers, :enabled_modules, :issue_statuses, :issues, 7 | :enumerations, :custom_fields, :custom_values, :custom_fields_trackers, 8 | :watchers, :journals, :journal_details, 9 | :custom_fields, :custom_fields_groups, :custom_fields_group_fields 10 | 11 | teardown do 12 | Setting.where(name: 'plugin_redmine_custom_fields_groups').destroy_all 13 | Setting.clear_cache 14 | end 15 | 16 | test 'click group title should collapse/expand fieldset with default state all_expended' do 17 | Setting.plugin_redmine_custom_fields_groups = { 18 | 'custom_fields_group_tag' => 'fieldset', 19 | 'fieldset_default_state' => 'all_expended' 20 | } 21 | 22 | log_user('dlopper', 'foo') 23 | visit '/issues/1' 24 | 25 | # issue details 26 | within('div.issue.details div.attributes') do 27 | assert page.has_content?('Group 1') 28 | # default expanded 29 | assert page.has_content?('Searchable field') 30 | assert page.has_content?('Database') 31 | # click group title 32 | find('fieldset.custom-fields-groups > legend.icon', :text => 'Group 1').click 33 | # collapsed fields 34 | assert page.has_no_content?('Searchable field') 35 | assert page.has_no_content?('Database') 36 | # click group title, again 37 | find('fieldset.custom-fields-groups > legend.icon', :text => 'Group 1').click 38 | # expanded fields 39 | assert page.has_content?('Searchable field') 40 | assert page.has_content?('Database') 41 | end 42 | 43 | # issue edit 44 | page.first(:link, 'Edit').click 45 | page.find('#issue_notes:focus') 46 | sleep 0.1 47 | within('div#update div.attributes') do 48 | assert page.has_content?('Group 1') 49 | # default expanded 50 | assert page.has_content?('Searchable field') 51 | assert page.has_content?('Database') 52 | # click group title 53 | find('fieldset.custom-fields-groups > legend.icon', :text => 'Group 1').click 54 | # collapsed fields 55 | assert page.has_no_content?('Searchable field') 56 | assert page.has_no_content?('Database') 57 | # click group title, again 58 | find('fieldset.custom-fields-groups > legend.icon', :text => 'Group 1').click 59 | # expanded fields 60 | assert page.has_content?('Searchable field') 61 | assert page.has_content?('Database') 62 | end 63 | end 64 | 65 | test 'click group title should expand/collapse fieldset with default state all_collapsed' do 66 | Setting.plugin_redmine_custom_fields_groups = { 67 | 'custom_fields_group_tag' => 'fieldset', 68 | 'fieldset_default_state' => 'all_collapsed' 69 | } 70 | 71 | log_user('dlopper', 'foo') 72 | visit '/issues/1' 73 | 74 | # issue details 75 | within('div.issue.details div.attributes') do 76 | assert page.has_content?('Group 1') 77 | # default collapsed 78 | assert page.has_no_content?('Searchable field') 79 | assert page.has_no_content?('Database') 80 | # click group title 81 | find('fieldset.custom-fields-groups > legend.icon', :text => 'Group 1').click 82 | # expanded fields 83 | assert page.has_content?('Searchable field') 84 | assert page.has_content?('Database') 85 | # click group title, again 86 | find('fieldset.custom-fields-groups > legend.icon', :text => 'Group 1').click 87 | # collapsed fields 88 | assert page.has_no_content?('Searchable field') 89 | assert page.has_no_content?('Database') 90 | end 91 | 92 | # issue edit 93 | page.first(:link, 'Edit').click 94 | page.find('#issue_notes:focus') 95 | sleep 0.1 96 | within('div#update div.attributes') do 97 | assert page.has_content?('Group 1') 98 | # default collapsed 99 | assert page.has_no_content?('Searchable field') 100 | assert page.has_no_content?('Database') 101 | # click group title 102 | find('fieldset.custom-fields-groups > legend.icon', :text => 'Group 1').click 103 | # expanded fields 104 | assert page.has_content?('Searchable field') 105 | assert page.has_content?('Database') 106 | # click group title, again 107 | find('fieldset.custom-fields-groups > legend.icon', :text => 'Group 1').click 108 | # collapsed fields 109 | assert page.has_no_content?('Searchable field') 110 | assert page.has_no_content?('Database') 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # Load the Redmine helper 2 | require_relative '../../../test/test_helper' 3 | 4 | ActiveRecord::FixtureSet.create_fixtures( 5 | File.dirname(__FILE__) + '/fixtures', 6 | ['custom_fields_groups', 'custom_fields_group_fields'] 7 | ) 8 | -------------------------------------------------------------------------------- /test/unit/custom_fields_group_field_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../test_helper' 2 | 3 | class CustomFieldsGroupFieldTest < ActiveSupport::TestCase 4 | 5 | # Replace this with your real tests. 6 | def test_truth 7 | assert true 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/unit/custom_fields_group_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../test_helper' 2 | 3 | class CustomFieldsGroupTest < ActiveSupport::TestCase 4 | fixtures :custom_fields, :custom_fields_groups, :custom_fields_group_fields 5 | 6 | test 'create' do 7 | issue_custom_field = IssueCustomField.new(:name => 'test', :field_format => 'text') 8 | issue_custom_field.save! 9 | issue_custom_field.reload 10 | 11 | custom_fields_group = CustomFieldsGroup.new 12 | custom_fields_group.name = 'test' 13 | custom_fields_group.custom_field_ids = [issue_custom_field.id] 14 | assert custom_fields_group.save 15 | custom_fields_group.reload 16 | assert_equal [issue_custom_field.id], custom_fields_group.custom_field_ids 17 | assert_equal CustomFieldsGroup.count, custom_fields_group.position 18 | end 19 | 20 | test 'should require name' do 21 | custom_fields_group = CustomFieldsGroup.new 22 | assert_not custom_fields_group.save 23 | assert custom_fields_group.errors[:name] 24 | end 25 | 26 | test 'should validate name uniqueness' do 27 | assert_difference 'CustomFieldsGroup.count' do 28 | custom_fields_group = CustomFieldsGroup.new 29 | custom_fields_group.name = 'test' 30 | assert custom_fields_group.save 31 | assert_equal 'test', custom_fields_group.name 32 | end 33 | 34 | assert_no_difference 'CustomFieldsGroup.count' do 35 | custom_fields_group = CustomFieldsGroup.new 36 | custom_fields_group.name = 'test' 37 | assert_not custom_fields_group.save 38 | assert custom_fields_group.errors[:name] 39 | end 40 | end 41 | 42 | test 'deletion of custom_field_group should delete custom_fields_group_field' do 43 | custom_fields_group = custom_fields_groups(:custom_fields_groups_100) 44 | assert_difference 'CustomFieldsGroupField.count', -2 do 45 | assert custom_fields_group.destroy 46 | end 47 | end 48 | 49 | test 'deletion of custom_field should delete custom_fields_group_field' do 50 | custom_field = custom_fields(:custom_fields_001) 51 | assert_difference 'CustomFieldsGroup.find(1).custom_fields.count', -1 do 52 | assert custom_field.destroy 53 | end 54 | end 55 | end 56 | --------------------------------------------------------------------------------