From 4cecc1beeda2337f50090d9fc0fe1d54fb8d54e2 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
@@ -42,9 +43,10 @@
<% end -%>
@@ -57,7 +59,8 @@
@@ -74,7 +77,8 @@
@@ -88,7 +92,7 @@
diff --git a/app/views/issues/_attributes.html.erb b/app/views/issues/_attributes.html.erb
index 0bec53163..d2c13e82b 100644
--- a/app/views/issues/_attributes.html.erb
+++ b/app/views/issues/_attributes.html.erb
@@ -64,3 +64,5 @@
<% end %>
<% end %>
+
+<% include_calendar_headers_tags %>
diff --git a/app/views/issues/bulk_edit.html.erb b/app/views/issues/bulk_edit.html.erb
index 946b5255b..63bc1f7df 100644
--- a/app/views/issues/bulk_edit.html.erb
+++ b/app/views/issues/bulk_edit.html.erb
@@ -33,28 +33,40 @@
<%= select_tag('issue[status_id]',content_tag('option', l(:label_no_change_option), :value => '') + options_from_collection_for_select(@available_statuses, :id, :name)) %>
<%= select_tag('issue[priority_id]', content_tag('option', l(:label_no_change_option), :value => '') + options_from_collection_for_select(IssuePriority.active, :id, :name)) %>
+<% end %> + +<% if @safe_attributes.include?('assigned_to_id') -%><%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') + content_tag('option', l(:label_nobody), :value => 'none') + principals_options_for_select(@assignables)) %>
+<% end %> + +<% if @safe_attributes.include?('category_id') -%><%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') + content_tag('option', l(:label_none), :value => 'none') + options_from_collection_for_select(@categories, :id, :name)) %>
+<% end %> + +<% if @safe_attributes.include?('fixed_version_id') -%><%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') + content_tag('option', l(:label_none), :value => 'none') + version_options_for_select(@versions.sort)) %>
+<% end %> <% @custom_fields.each do |custom_field| %><%= custom_field_tag_for_bulk_edit('issue', custom_field, @projects) %>
@@ -79,7 +91,8 @@ content_tag('option', l(:general_text_No), :value => '0')) %> <% end %> -<% if @project && User.current.allowed_to?(:manage_subtasks, @project) %> + +<% if @safe_attributes.include?('parent_issue_id') && @project %><%= text_field_tag 'issue[parent_issue_id]', '', :size => 10 %> @@ -87,15 +100,22 @@
<%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:project_id => @project) }')" %> <% end %> + +<% if @safe_attributes.include?('start_date') %><%= text_field_tag 'issue[start_date]', '', :size => 10 %><%= calendar_for('issue_start_date') %>
+<% end %> + +<% if @safe_attributes.include?('due_date') %><%= text_field_tag 'issue[due_date]', '', :size => 10 %><%= calendar_for('issue_due_date') %>
-<% if Issue.use_field_for_done_ratio? %> +<% end %> + +<% if @safe_attributes.include?('done_ratio') && Issue.use_field_for_done_ratio? %><%= select_tag 'issue[done_ratio]', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %> diff --git a/app/views/issues/show.html.erb b/app/views/issues/show.html.erb index 96e59b451..4f53592b0 100644 --- a/app/views/issues/show.html.erb +++ b/app/views/issues/show.html.erb @@ -32,34 +32,36 @@
| <%=l(:field_status)%>: | <%= h(@issue.status.name) %> | -<%=l(:field_start_date)%>: | <%= format_date(@issue.start_date) %> | -||
|---|---|---|---|---|---|
| <%=l(:field_priority)%>: | <%= h(@issue.priority.name) %> | -<%=l(:field_due_date)%>: | <%= format_date(@issue.due_date) %> | -||
| <%=l(:field_assigned_to)%>: | <%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %> | -<%=l(:field_done_ratio)%>: | <%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %> | -||
| <%=l(:field_category)%>: | <%=h(@issue.category ? @issue.category.name : "-") %> | - <% if User.current.allowed_to?(:view_time_entries, @project) %> -<%=l(:label_spent_time)%>: | -<%= @issue.total_spent_hours > 0 ? (link_to l_hours(@issue.total_spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-" %> | - <% else %> -- | - <% end %> - |
| <%=l(:field_fixed_version)%>: | <%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %> | - <% if @issue.estimated_hours %> -<%=l(:field_estimated_hours)%>: | <%= l_hours(@issue.estimated_hours) %> | - <% end %> -
<%= f.text_field :name, :required => true %>
<%= f.check_box :is_in_roadmap %>
++ + <% Tracker::CORE_FIELDS.each do |field| %> + + <% end %> +
+<%= hidden_field_tag 'tracker[core_fields][]', '' %> + <% if IssueCustomField.all.any? %>diff --git a/config/locales/en.yml b/config/locales/en.yml index 25f2ca716..03a850677 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -328,6 +328,7 @@ en: field_repository_is_default: Main repository field_multiple: Multiple values field_ldap_filter: LDAP filter + field_core_fields: Standard fields setting_app_title: Application title setting_app_subtitle: Application subtitle diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 5f9504b09..b341da627 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -327,6 +327,7 @@ fr: field_repository_is_default: Dépôt principal field_multiple: Valeurs multiples field_ldap_filter: Filtre LDAP + field_core_fields: Champs standards setting_app_title: Titre de l'application setting_app_subtitle: Sous-titre de l'application diff --git a/db/migrate/20120705074331_add_trackers_fields_bits.rb b/db/migrate/20120705074331_add_trackers_fields_bits.rb new file mode 100644 index 000000000..5d8458382 --- /dev/null +++ b/db/migrate/20120705074331_add_trackers_fields_bits.rb @@ -0,0 +1,9 @@ +class AddTrackersFieldsBits < ActiveRecord::Migration + def self.up + add_column :trackers, :fields_bits, :integer, :default => 0 + end + + def self.down + remove_column :trackers, :fields_bits + end +end diff --git a/lib/redmine/export/pdf.rb b/lib/redmine/export/pdf.rb index 39ac46824..466b0ccac 100644 --- a/lib/redmine/export/pdf.rb +++ b/lib/redmine/export/pdf.rb @@ -18,6 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require 'iconv' +require 'tcpdf' require 'fpdf/chinese' require 'fpdf/japanese' require 'fpdf/korean' @@ -497,14 +498,13 @@ module Redmine # Returns a PDF string of a single issue def issue_to_pdf(issue) pdf = ITCPDF.new(current_language) - pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}") + pdf.SetTitle("#{issue.project} - #{issue.tracker} ##{issue.id}") pdf.alias_nb_pages pdf.footer_date = format_date(Date.today) pdf.AddPage pdf.SetFontStyle('B',11) - buf = "#{issue.project} - #{issue.tracker} # #{issue.id}" + buf = "#{issue.project} - #{issue.tracker} ##{issue.id}" pdf.RDMMultiCell(190, 5, buf) - pdf.Ln pdf.SetFontStyle('',8) base_x = pdf.GetX i = 1 @@ -514,62 +514,54 @@ module Redmine pdf.RDMMultiCell(190 - i, 5, buf) i += 1 if i < 35 end + pdf.SetFontStyle('B',11) + pdf.RDMMultiCell(190 - i, 5, issue.subject.to_s) + pdf.SetFontStyle('',8) + pdf.RDMMultiCell(190, 5, "#{format_time(issue.created_on)} - #{issue.author}") pdf.Ln - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_status) + ":","LT") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, issue.status.to_s,"RT") - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_priority) + ":","LT") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, issue.priority.to_s,"RT") - pdf.Ln + left = [] + left << [l(:field_status), issue.status] + left << [l(:field_priority), issue.priority] + left << [l(:field_assigned_to), issue.assigned_to] unless issue.disabled_core_fields.include?('assigned_to_id') + left << [l(:field_category), issue.category] unless issue.disabled_core_fields.include?('category_id') + left << [l(:field_fixed_version), issue.fixed_version] unless issue.disabled_core_fields.include?('fixed_version_id') - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_author) + ":","L") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, issue.author.to_s,"R") - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_category) + ":","L") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, issue.category.to_s,"R") - pdf.Ln + right = [] + right << [l(:field_start_date), format_date(issue.start_date)] unless issue.disabled_core_fields.include?('start_date') + right << [l(:field_due_date), format_date(issue.due_date)] unless issue.disabled_core_fields.include?('due_date') + right << [l(:field_done_ratio), "#{issue.done_ratio}%"] unless issue.disabled_core_fields.include?('done_ratio') + right << [l(:field_estimated_hours), l_hours(issue.estimated_hours)] unless issue.disabled_core_fields.include?('estimated_hours') + right << [l(:label_spent_time), l_hours(issue.total_spent_hours)] if User.current.allowed_to?(:view_time_entries, issue.project) - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_created_on) + ":","L") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, format_date(issue.created_on),"R") - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, issue.assigned_to.to_s,"R") - pdf.Ln - - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, format_date(issue.updated_on),"RB") - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_due_date) + ":","LB") - pdf.SetFontStyle('',9) - pdf.RDMCell(60,5, format_date(issue.due_date),"RB") - pdf.Ln - - for custom_value in issue.custom_field_values - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L") - pdf.SetFontStyle('',9) - pdf.RDMMultiCell(155,5, (show_value custom_value),"R") + rows = left.size > right.size ? left.size : right.size + while left.size < rows + left << nil + end + while right.size < rows + right << nil end - y0 = pdf.GetY + half = (issue.custom_field_values.size / 2.0).ceil + issue.custom_field_values.each_with_index do |custom_value, i| + (i < half ? left : right) << [custom_value.custom_field.name, show_value(custom_value)] + end - pdf.SetFontStyle('B',9) - pdf.RDMCell(35,5, l(:field_subject) + ":","LT") - pdf.SetFontStyle('',9) - pdf.RDMMultiCell(155,5, issue.subject,"RT") - pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY) + rows = left.size > right.size ? left.size : right.size + rows.times do |i| + item = left[i] + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, item ? "#{item.first}:" : "", i == 0 ? "LT" : "L") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, item ? item.last.to_s : "", i == 0 ? "RT" : "R") + + item = right[i] + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, item ? "#{item.first}:" : "", i == 0 ? "LT" : "L") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, item ? item.last.to_s : "", i == 0 ? "RT" : "R") + pdf.Ln + end pdf.SetFontStyle('B',9) pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1) diff --git a/test/functional/trackers_controller_test.rb b/test/functional/trackers_controller_test.rb index 731d19b52..7393088ae 100644 --- a/test/functional/trackers_controller_test.rb +++ b/test/functional/trackers_controller_test.rb @@ -64,10 +64,21 @@ class TrackersControllerTest < ActionController::TestCase tracker = Tracker.first(:order => 'id DESC') assert_equal 'New tracker', tracker.name assert_equal [1], tracker.project_ids.sort + assert_equal Tracker::CORE_FIELDS, tracker.core_fields assert_equal [1, 6], tracker.custom_field_ids.sort assert_equal 0, tracker.workflows.count end + def create_with_disabled_core_fields + assert_difference 'Tracker.count' do + post :create, :tracker => { :name => 'New tracker', :core_fields => ['assigned_to_id', 'fixed_version_id', ''] } + end + assert_redirected_to :action => 'index' + tracker = Tracker.first(:order => 'id DESC') + assert_equal 'New tracker', tracker.name + assert_equal %w(assigned_to_id fixed_version_id), tracker.core_fields + end + def test_create_new_with_workflow_copy assert_difference 'Tracker.count' do post :create, :tracker => { :name => 'New tracker' }, :copy_workflow_from => 1 @@ -107,6 +118,24 @@ class TrackersControllerTest < ActionController::TestCase :type => 'hidden'} end + def test_edit_should_check_core_fields + tracker = Tracker.find(1) + tracker.core_fields = %w(assigned_to_id fixed_version_id) + tracker.save! + + get :edit, :id => 1 + assert_response :success + assert_template 'edit' + + assert_select 'input[name=?][value=assigned_to_id][checked=checked]', 'tracker[core_fields][]' + assert_select 'input[name=?][value=fixed_version_id][checked=checked]', 'tracker[core_fields][]' + + assert_select 'input[name=?][value=category_id]', 'tracker[core_fields][]' + assert_select 'input[name=?][value=category_id][checked=checked]', 'tracker[core_fields][]', 0 + + assert_select 'input[name=?][value=][type=hidden]', 'tracker[core_fields][]' + end + def test_update put :update, :id => 1, :tracker => { :name => 'Renamed', :project_ids => ['1', '2', ''] } @@ -121,6 +150,12 @@ class TrackersControllerTest < ActionController::TestCase assert Tracker.find(1).project_ids.empty? end + def test_update_without_core_fields + put :update, :id => 1, :tracker => { :name => 'Renamed', :core_fields => [''] } + assert_redirected_to :action => 'index' + assert Tracker.find(1).core_fields.empty? + end + def test_update_with_failure put :update, :id => 1, :tracker => { :name => '' } assert_response :success diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index b5799f3fc..fe8bdf2ac 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -403,6 +403,52 @@ class IssueTest < ActiveSupport::TestCase assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id) end + def test_safe_attributes_should_not_include_disabled_field + tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id)) + + issue = Issue.new(:tracker => tracker) + assert_include 'tracker_id', issue.safe_attribute_names + assert_include 'status_id', issue.safe_attribute_names + assert_include 'subject', issue.safe_attribute_names + assert_include 'description', issue.safe_attribute_names + assert_include 'custom_field_values', issue.safe_attribute_names + assert_include 'custom_fields', issue.safe_attribute_names + assert_include 'lock_version', issue.safe_attribute_names + + tracker.core_fields.each do |field| + assert_include field, issue.safe_attribute_names + end + + tracker.disabled_core_fields.each do |field| + assert_not_include field, issue.safe_attribute_names + end + end + + def test_safe_attributes_should_ignore_disabled_fields + tracker = Tracker.find(1) + tracker.core_fields = %w(assigned_to_id due_date) + tracker.save! + + issue = Issue.new(:tracker => tracker) + issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'} + assert_nil issue.start_date + assert_equal Date.parse('2012-07-14'), issue.due_date + end + + def test_safe_attributes_should_accept_target_tracker_fields + source = Tracker.find(1) + source.core_fields = [] + source.save! + target = Tracker.find(2) + target.core_fields = %w(assigned_to_id due_date) + target.save! + + issue = Issue.new(:tracker => source) + issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'} + assert_equal target, issue.tracker + assert_equal Date.parse('2012-07-14'), issue.due_date + end + def test_copy issue = Issue.new.copy_from(1) assert issue.copy? diff --git a/test/unit/tracker_test.rb b/test/unit/tracker_test.rb index 9cf6866a9..91b259827 100644 --- a/test/unit/tracker_test.rb +++ b/test/unit/tracker_test.rb @@ -59,6 +59,30 @@ class TrackerTest < ActiveSupport::TestCase assert_equal [], Tracker.new.issue_statuses end + def test_core_fields_should_be_enabled_by_default + tracker = Tracker.new + assert_equal Tracker::CORE_FIELDS, tracker.core_fields + assert_equal [], tracker.disabled_core_fields + end + + def test_core_fields + tracker = Tracker.new + tracker.core_fields = %w(assigned_to_id due_date) + + assert_equal %w(assigned_to_id due_date), tracker.core_fields + assert_equal Tracker::CORE_FIELDS - %w(assigned_to_id due_date), tracker.disabled_core_fields + end + + def test_core_fields_should_return_fields_enabled_for_any_tracker + trackers = [] + trackers << Tracker.new(:core_fields => %w(assigned_to_id due_date)) + trackers << Tracker.new(:core_fields => %w(assigned_to_id done_ratio)) + trackers << Tracker.new(:core_fields => []) + + assert_equal %w(assigned_to_id due_date done_ratio), Tracker.core_fields(trackers) + assert_equal Tracker::CORE_FIELDS - %w(assigned_to_id due_date done_ratio), Tracker.disabled_core_fields(trackers) + end + def test_sort_should_sort_by_position a = Tracker.new(:name => 'Tracker A', :position => 2) b = Tracker.new(:name => 'Tracker B', :position => 1)