diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2006-11-27 22:31:14 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2006-11-27 22:31:14 +0000 |
commit | 42181112ff73822afe5c0f96e065ae372f392e47 (patch) | |
tree | 6ad09ba882eda77f29ddbcf920bd1724b0b25366 /redmine | |
parent | 67e81b0ae9f2a63e10d28c4ea29edd34c7c34f00 (diff) | |
download | redmine-42181112ff73822afe5c0f96e065ae372f392e47.tar.gz redmine-42181112ff73822afe5c0f96e065ae372f392e47.zip |
improved issues change history
git-svn-id: http://redmine.rubyforge.org/svn/trunk@54 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'redmine')
38 files changed, 389 insertions, 153 deletions
diff --git a/redmine/app/controllers/application.rb b/redmine/app/controllers/application.rb index e1e842b0b..3bebf4de5 100644 --- a/redmine/app/controllers/application.rb +++ b/redmine/app/controllers/application.rb @@ -41,7 +41,7 @@ class ApplicationController < ActionController::Base if self.logged_in_user and self.logged_in_user.language and !self.logged_in_user.language.empty? and GLoc.valid_languages.include? self.logged_in_user.language.to_sym
self.logged_in_user.language
elsif request.env['HTTP_ACCEPT_LANGUAGE']
- accept_lang = HTTPUtils.parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.split('-').first
+ accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.split('-').first
if accept_lang and !accept_lang.empty? and GLoc.valid_languages.include? accept_lang.to_sym
accept_lang
end
@@ -104,4 +104,23 @@ class ApplicationController < ActionController::Base session[:return_to] = nil end end +
+ # qvalues http header parser
+ # code taken from webrick
+ def parse_qvalues(value)
+ tmp = []
+ if value
+ parts = value.split(/,\s*/)
+ parts.each {|part|
+ if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part)
+ val = m[1]
+ q = (m[2] or 1).to_f
+ tmp.push([val, q])
+ end
+ }
+ tmp = tmp.sort_by{|val, q| -q}
+ tmp.collect!{|val, q| val}
+ end
+ return tmp
+ end
end
\ No newline at end of file diff --git a/redmine/app/controllers/issues_controller.rb b/redmine/app/controllers/issues_controller.rb index 45b4fe633..e196e8226 100644 --- a/redmine/app/controllers/issues_controller.rb +++ b/redmine/app/controllers/issues_controller.rb @@ -27,6 +27,13 @@ class IssuesController < ApplicationController def show @status_options = @issue.status.workflows.find(:all, :include => :new_status, :conditions => ["role_id=? and tracker_id=?", self.logged_in_user.role_for_project(@project.id), @issue.tracker.id]).collect{ |w| w.new_status } if self.logged_in_user
@custom_values = @issue.custom_values.find(:all, :include => :custom_field)
+ @journals_count = @issue.journals.count
+ @journals = @issue.journals.find(:all, :include => [:user, :details], :limit => 15, :order => "journals.created_on desc")
+ end
+
+ def history
+ @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "journals.created_on desc")
+ @journals_count = @journals.length
end
def export_pdf
@@ -41,6 +48,7 @@ class IssuesController < ApplicationController @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) }
else
begin
+ @issue.init_journal(self.logged_in_user)
# Retrieve custom fields and values
@custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
@issue.custom_values = @custom_values
@@ -57,13 +65,14 @@ class IssuesController < ApplicationController end
def add_note
- unless params[:history][:notes].empty?
- @history = @issue.histories.build(params[:history])
- @history.author_id = self.logged_in_user.id if self.logged_in_user
- @history.status = @issue.status
- if @history.save
+ unless params[:notes].empty?
+ journal = @issue.init_journal(self.logged_in_user, params[:notes])
+ #@history = @issue.histories.build(params[:history])
+ #@history.author_id = self.logged_in_user.id if self.logged_in_user
+ #@history.status = @issue.status
+ if @issue.save
flash[:notice] = l(:notice_successful_update)
- Mailer.deliver_issue_add_note(@history) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled?
+ Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled?
redirect_to :action => 'show', :id => @issue
return
end
@@ -73,17 +82,20 @@ class IssuesController < ApplicationController end
def change_status
- @history = @issue.histories.build(params[:history])
+ #@history = @issue.histories.build(params[:history])
@status_options = @issue.status.workflows.find(:all, :conditions => ["role_id=? and tracker_id=?", self.logged_in_user.role_for_project(@project.id), @issue.tracker.id]).collect{ |w| w.new_status } if self.logged_in_user
+ @new_status = IssueStatus.find(params[:new_status_id])
if params[:confirm]
begin
- @history.author_id = self.logged_in_user.id if self.logged_in_user
- @issue.status = @history.status
- @issue.fixed_version_id = (params[:issue][:fixed_version_id])
- @issue.assigned_to_id = (params[:issue][:assigned_to_id])
- @issue.done_ratio = (params[:issue][:done_ratio])
- @issue.lock_version = (params[:issue][:lock_version])
- if @issue.save
+ #@history.author_id = self.logged_in_user.id if self.logged_in_user
+ #@issue.status = @history.status
+ #@issue.fixed_version_id = (params[:issue][:fixed_version_id])
+ #@issue.assigned_to_id = (params[:issue][:assigned_to_id])
+ #@issue.done_ratio = (params[:issue][:done_ratio])
+ #@issue.lock_version = (params[:issue][:lock_version])
+ @issue.init_journal(self.logged_in_user, params[:notes])
+ @issue.status = @new_status
+ if @issue.update_attributes(params[:issue])
flash[:notice] = l(:notice_successful_update)
Mailer.deliver_issue_change_status(@issue) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled?
redirect_to :action => 'show', :id => @issue
diff --git a/redmine/app/controllers/projects_controller.rb b/redmine/app/controllers/projects_controller.rb index a2b7abb4d..c968800c3 100644 --- a/redmine/app/controllers/projects_controller.rb +++ b/redmine/app/controllers/projects_controller.rb @@ -28,6 +28,7 @@ class ProjectsController < ApplicationController include CustomFieldsHelper
helper :ifpdf
include IfpdfHelper
+ helper IssuesHelper
def index list diff --git a/redmine/app/helpers/application_helper.rb b/redmine/app/helpers/application_helper.rb index 378545eb1..0f0deeb30 100644 --- a/redmine/app/helpers/application_helper.rb +++ b/redmine/app/helpers/application_helper.rb @@ -81,7 +81,7 @@ module ApplicationHelper end
def textilizable(text)
- $RDM_TEXTILE_DISABLED ? text : textilize(text)
+ $RDM_TEXTILE_DISABLED ? text : RedCloth.new(text).to_html
end
def error_messages_for(object_name, options = {})
diff --git a/redmine/app/helpers/custom_fields_helper.rb b/redmine/app/helpers/custom_fields_helper.rb index 38cb9df5e..9df5c50a3 100644 --- a/redmine/app/helpers/custom_fields_helper.rb +++ b/redmine/app/helpers/custom_fields_helper.rb @@ -54,15 +54,20 @@ module CustomFieldsHelper # Return a string used to display a custom value
def show_value(custom_value)
return "" unless custom_value
-
- case custom_value.custom_field.field_format
+ format_value(custom_value.value, custom_value.custom_field.field_format)
+ end
+
+ # Return a string used to display a custom value
+ def format_value(value, field_format)
+ return "" unless value
+ case field_format
when "date"
- custom_value.value.empty? ? "" : l_date(custom_value.value.to_date)
+ value.empty? ? "" : l_date(value.to_date)
when "bool"
- l_YesNo(custom_value.value == "1")
+ l_YesNo(value == "1")
else
- custom_value.value
- end
+ value
+ end
end
# Return an array of custom field formats which can be used in select_tag
diff --git a/redmine/app/helpers/ifpdf_helper.rb b/redmine/app/helpers/ifpdf_helper.rb index 4e7a173f4..a0dab0f94 100644 --- a/redmine/app/helpers/ifpdf_helper.rb +++ b/redmine/app/helpers/ifpdf_helper.rb @@ -25,12 +25,12 @@ module IfpdfHelper def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='')
@ic ||= Iconv.new('ISO-8859-1', 'UTF-8')
- super w,h,@ic.iconv(txt),border,ln,align,fill,link
- end
-
- def MultiCell(w,h,txt,border=0,align='J',fill=0)
- @ic ||= Iconv.new('ISO-8859-1', 'UTF-8')
- super w,h,txt,border,align,fill
+ txt = begin
+ @ic.iconv(txt)
+ rescue
+ txt
+ end
+ super w,h,txt,border,ln,align,fill,link
end
def Footer
diff --git a/redmine/app/helpers/issues_helper.rb b/redmine/app/helpers/issues_helper.rb index 40c0e40ae..93bd6c050 100644 --- a/redmine/app/helpers/issues_helper.rb +++ b/redmine/app/helpers/issues_helper.rb @@ -15,5 +15,60 @@ # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-module IssuesHelper +module IssuesHelper
+
+ def show_detail(detail, no_html=false)
+ case detail.property
+ when 'attr'
+ label = l(("field_" + detail.prop_key.to_s.gsub(/\_id$/, "")).to_sym)
+ case detail.prop_key
+ when 'due_date', 'start_date'
+ value = format_date(detail.value.to_date) if detail.value
+ old_value = format_date(detail.old_value.to_date) if detail.old_value
+ when 'status_id'
+ s = IssueStatus.find_by_id(detail.value) and value = s.name if detail.value
+ s = IssueStatus.find_by_id(detail.old_value) and old_value = s.name if detail.old_value
+ when 'assigned_to_id'
+ u = User.find_by_id(detail.value) and value = u.name if detail.value
+ u = User.find_by_id(detail.old_value) and old_value = u.name if detail.old_value
+ when 'priority_id'
+ e = Enumeration.find_by_id(detail.value) and value = e.name if detail.value
+ e = Enumeration.find_by_id(detail.old_value) and old_value = e.name if detail.old_value
+ when 'category_id'
+ c = IssueCategory.find_by_id(detail.value) and value = c.name if detail.value
+ c = IssueCategory.find_by_id(detail.old_value) and old_value = c.name if detail.old_value
+ when 'fixed_version_id'
+ v = Version.find_by_id(detail.value) and value = v.name if detail.value
+ v = Version.find_by_id(detail.old_value) and old_value = v.name if detail.old_value
+ end
+ when 'cf'
+ custom_field = CustomField.find_by_id(detail.prop_key)
+ if custom_field
+ label = custom_field.name
+ value = format_value(detail.value, custom_field.field_format) if detail.value
+ old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value
+ end
+ end
+
+ label ||= detail.prop_key
+ value ||= detail.value
+ old_value ||= detail.old_value
+
+ unless no_html
+ label = content_tag('strong', label)
+ old_value = content_tag("i", old_value) if old_value
+ old_value = content_tag("strike", old_value) if old_value and !value
+ value = content_tag("i", value) if value
+ end
+
+ if value
+ if old_value
+ label + " " + l(:text_journal_changed, old_value, value)
+ else
+ label + " " + l(:text_journal_set_to, value)
+ end
+ else
+ label + " " + l(:text_journal_deleted) + " (#{old_value})"
+ end
+ end end diff --git a/redmine/app/models/issue.rb b/redmine/app/models/issue.rb index 4834e069f..f00eb7a9c 100644 --- a/redmine/app/models/issue.rb +++ b/redmine/app/models/issue.rb @@ -26,7 +26,8 @@ class Issue < ActiveRecord::Base belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id'
belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
- has_many :histories, :class_name => 'IssueHistory', :dependent => true, :order => "issue_histories.created_on DESC", :include => :status
+ #has_many :histories, :class_name => 'IssueHistory', :dependent => true, :order => "issue_histories.created_on DESC", :include => :status
+ has_many :journals, :as => :journalized, :dependent => true
has_many :attachments, :as => :container, :dependent => true
has_many :custom_values, :dependent => true, :as => :customized
@@ -51,8 +52,28 @@ class Issue < ActiveRecord::Base end
end
- def before_create
- build_history
+ #def before_create
+ # build_history
+ #end
+
+ def before_save
+ if @current_journal
+ # attributes changes
+ (Issue.column_names - %w(id description)).each {|c|
+ @current_journal.details << JournalDetail.new(:property => 'attr',
+ :prop_key => c,
+ :old_value => @issue_before_change.send(c),
+ :value => send(c)) unless send(c)==@issue_before_change.send(c)
+ }
+ # custom fields changes
+ custom_values.each {|c|
+ @current_journal.details << JournalDetail.new(:property => 'cf',
+ :prop_key => c.custom_field_id,
+ :old_value => @custom_values_before_change[c.custom_field_id],
+ :value => c.value) unless @custom_values_before_change[c.custom_field_id]==c.value
+ }
+ @current_journal.save unless @current_journal.details.empty? and @current_journal.notes.empty?
+ end
end
def long_id
@@ -63,12 +84,20 @@ class Issue < ActiveRecord::Base self.custom_values.each {|v| return v if v.custom_field_id == custom_field.id }
return nil
end
+
+ def init_journal(user, notes = "")
+ @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes)
+ @issue_before_change = self.clone
+ @custom_values_before_change = {}
+ self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
+ @current_journal
+ end
private
# Creates an history for the issue
- def build_history
- @history = self.histories.build
- @history.status = self.status
- @history.author = self.author
- end
+ #def build_history
+ # @history = self.histories.build
+ # @history.status = self.status
+ # @history.author = self.author
+ #end
end diff --git a/redmine/app/models/journal.rb b/redmine/app/models/journal.rb new file mode 100644 index 000000000..9d173552f --- /dev/null +++ b/redmine/app/models/journal.rb @@ -0,0 +1,22 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Journal < ActiveRecord::Base + belongs_to :journalized, :polymorphic => true + belongs_to :user + has_many :details, :class_name => "JournalDetail", :dependent => true +end diff --git a/redmine/app/models/journal_detail.rb b/redmine/app/models/journal_detail.rb new file mode 100644 index 000000000..784e98bf7 --- /dev/null +++ b/redmine/app/models/journal_detail.rb @@ -0,0 +1,20 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class JournalDetail < ActiveRecord::Base + belongs_to :journal +end diff --git a/redmine/app/models/mailer.rb b/redmine/app/models/mailer.rb index fa19bf4da..bbe782526 100644 --- a/redmine/app/models/mailer.rb +++ b/redmine/app/models/mailer.rb @@ -17,14 +17,6 @@ class Mailer < ActionMailer::Base - def issue_change_status(issue) - # Sends to all project members - @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification } - @from = $RDM_MAIL_FROM - @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}"
- @body['issue'] = issue
- end
-
def issue_add(issue) # Sends to all project members @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification } @@ -33,12 +25,14 @@ class Mailer < ActionMailer::Base @body['issue'] = issue
end
- def issue_add_note(history)
+ def issue_edit(journal)
# Sends to all project members
- @recipients = history.issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }
+ issue = journal.journalized
+ @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }
@from = $RDM_MAIL_FROM
- @subject = "[#{history.issue.project.name} - #{history.issue.tracker.name} ##{history.issue.id}] #{history.issue.status.name} - #{history.issue.subject}"
- @body['history'] = history
+ @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}"
+ @body['issue'] = issue
+ @body['journal']= journal
end
def lost_password(token)
diff --git a/redmine/app/views/issues/_history.rhtml b/redmine/app/views/issues/_history.rhtml new file mode 100644 index 000000000..6dc2a84be --- /dev/null +++ b/redmine/app/views/issues/_history.rhtml @@ -0,0 +1,11 @@ +<% for journal in journals %>
+ <h4><%= format_time(journal.created_on) %> - <%= journal.user.name %></h4>
+ <ul>
+ <% for detail in journal.details %>
+ <li><%= show_detail(detail) %></li>
+ <% end %>
+ </ul>
+ <% if journal.notes? %>
+ <%= simple_format auto_link journal.notes %>
+ <% end %>
+<% end %>
diff --git a/redmine/app/views/issues/_pdf.rfpdf b/redmine/app/views/issues/_pdf.rfpdf index d12db0a23..1f6a12283 100644 --- a/redmine/app/views/issues/_pdf.rfpdf +++ b/redmine/app/views/issues/_pdf.rfpdf @@ -66,29 +66,34 @@ pdf.Line(pdf.GetX, pdf.GetY, 170, pdf.GetY)
pdf.Ln
+
pdf.SetFont('Arial','B',9)
- pdf.Cell(190,5, l(:label_history),"B")
- pdf.Ln
- for history in issue.histories.find(:all, :include => [:author, :status])
- pdf.SetFont('Arial','B',8)
- pdf.Cell(100,5, history.status.name)
- pdf.SetFont('Arial','',8)
- pdf.Cell(20,5, format_date(history.created_on))
- pdf.Cell(70,5, history.author.name,0,0,"R")
- pdf.SetFont('Arial','',8)
+ pdf.Cell(190,5, l(:label_history), "B")
+ pdf.Ln
+ for journal in issue.journals.find(:all, :include => :user, :order => "journals.created_on desc")
+ pdf.SetFont('Arial','B',8)
+ pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name)
pdf.Ln
- pdf.Cell(10,4, "") and pdf.MultiCell(180,4, history.notes) if history.notes?
+ pdf.SetFont('Arial','I',8)
+ for detail in journal.details
+ pdf.Cell(190,5, "- " + show_detail(detail, true))
+ pdf.Ln
+ end
+ if journal.notes?
+ pdf.SetFont('Arial','',8)
+ pdf.MultiCell(190,5, journal.notes)
+ end
+ pdf.Ln
end
- pdf.Ln
-
+
pdf.SetFont('Arial','B',9)
pdf.Cell(190,5, l(:label_attachment_plural), "B")
- pdf.Ln
+ pdf.Ln
for attachment in issue.attachments
pdf.SetFont('Arial','',8)
pdf.Cell(80,5, attachment.filename)
- pdf.Cell(20,5, human_size(attachment.filesize))
- pdf.Cell(20,5, format_date(attachment.created_on))
+ pdf.Cell(20,5, human_size(attachment.filesize),0,0,"R")
+ pdf.Cell(20,5, format_date(attachment.created_on),0,0,"R")
pdf.Cell(70,5, attachment.author.name,0,0,"R")
pdf.Ln
end
diff --git a/redmine/app/views/issues/change_status.rhtml b/redmine/app/views/issues/change_status.rhtml index 0fe07ad23..2ef87183d 100644 --- a/redmine/app/views/issues/change_status.rhtml +++ b/redmine/app/views/issues/change_status.rhtml @@ -1,13 +1,13 @@ <h2><%=l(:label_issue)%> #<%= @issue.id %>: <%= @issue.subject %></h2> -<%= error_messages_for 'history' %>
+<%= error_messages_for 'issue' %>
<%= start_form_tag({:action => 'change_status', :id => @issue}, :class => "tabular") %>
<%= hidden_field_tag 'confirm', 1 %>
-<%= hidden_field 'history', 'status_id' %> +<%= hidden_field_tag 'new_status_id', @new_status.id %> <div class="box">
-<p><label><%=l(:label_issue_status_new)%></label> <%= @history.status.name %></p>
+<p><label><%=l(:label_issue_status_new)%></label> <%= @new_status.name %></p>
<p><label for="issue_assigned_to_id"><%=l(:field_assigned_to)%></label> <select name="issue[assigned_to_id]">
@@ -25,12 +25,13 @@ <select name="issue[fixed_version_id]">
<option value="">--none--</option>
<%= options_from_collection_for_select @issue.project.versions, "id", "name", @issue.fixed_version_id %>
-</select></p>
-
-<p><label for="history_notes"><%=l(:field_notes)%></label>
-<%= text_area 'history', 'notes', :cols => 60, :rows => 10 %></p>
-</div> +</select></p> +<p><label for="notes"><%= l(:field_notes) %></label> +<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10 %></p> + +</div> +
<%= hidden_field 'issue', 'lock_version' %> <%= submit_tag l(:button_save) %>
<%= end_form_tag %>
diff --git a/redmine/app/views/issues/edit.rhtml b/redmine/app/views/issues/edit.rhtml index 6044fa9fd..60cdafc1e 100644 --- a/redmine/app/views/issues/edit.rhtml +++ b/redmine/app/views/issues/edit.rhtml @@ -19,7 +19,7 @@ <div class="clear"> <p><%= f.text_field :subject, :size => 80, :required => true %></p> -<p><%= f.text_area :description, :cols => 60, :rows => 10, :required => true %></p> +<p><%= f.text_area :description, :cols => 60, :rows => [[10, @issue.description.length / 50].max, 100].min, :required => true %></p> <% for @custom_value in @custom_values %> <p><%= custom_field_tag_with_label @custom_value %></p> diff --git a/redmine/app/views/issues/history.rhtml b/redmine/app/views/issues/history.rhtml new file mode 100644 index 000000000..2443cc739 --- /dev/null +++ b/redmine/app/views/issues/history.rhtml @@ -0,0 +1,6 @@ +<h3><%=l(:label_history)%></h3>
+<div id="history">
+<%= render :partial => 'history', :locals => { :journals => @journals } %>
+</div>
+<br />
+<p><%= link_to l(:button_back), :action => 'show', :id => @issue %></p>
\ No newline at end of file diff --git a/redmine/app/views/issues/show.rhtml b/redmine/app/views/issues/show.rhtml index 43b7d0449..8128b74a9 100644 --- a/redmine/app/views/issues/show.rhtml +++ b/redmine/app/views/issues/show.rhtml @@ -44,8 +44,8 @@ end %> <b><%=l(:field_description)%> :</b><br /><br />
<%= textilizable @issue.description %>
-
-<p>
+<br />
+<div style="float:left;">
<% if authorize_for('issues', 'edit') %>
<%= start_form_tag ({:controller => 'issues', :action => 'edit', :id => @issue}, :method => "get" ) %>
<%= submit_tag l(:button_edit) %>
@@ -56,7 +56,7 @@ end %> <% if authorize_for('issues', 'change_status') and @status_options and !@status_options.empty? %>
<%= start_form_tag ({:controller => 'issues', :action => 'change_status', :id => @issue}) %>
<%=l(:label_change_status)%> :
- <select name="history[status_id]">
+ <select name="new_status_id">
<%= options_from_collection_for_select @status_options, "id", "name" %>
</select>
<%= submit_tag l(:button_change) %>
@@ -71,30 +71,25 @@ end %> <%= end_form_tag %>
<% end %>
-
+</div>
+<div style="float:right;">
<% if authorize_for('issues', 'destroy') %>
<%= start_form_tag ({:controller => 'issues', :action => 'destroy', :id => @issue} ) %>
<%= submit_tag l(:button_delete) %>
<%= end_form_tag %>
<% end %>
-</p>
+</div>
+<div class="clear"></div>
</div>
-<div class="box">
-<h3><%=l(:label_history)%></h3>
-<table width="100%">
-<% for history in @issue.histories.find(:all, :include => [:author, :status]) %>
-<tr>
-<td><%= format_date(history.created_on) %></td>
-<td><%= history.author.display_name %></td>
-<td><b><%= history.status.name %></b></td>
-</tr>
-<% if history.notes? %>
- <tr><td colspan=3><%= simple_format auto_link history.notes %></td></tr>
-<% end %>
+<div id="history" class="box">
+<h3><%=l(:label_history)%>
+<% if @journals_count > @journals.length %>(<%= l(:label_last_changes, @journals.length) %>)<% end %></h3>
+<%= render :partial => 'history', :locals => { :journals => @journals } %>
+<% if @journals_count > @journals.length %>
+ <p><center><small>[ <%= link_to l(:label_change_view_all), :action => 'history', :id => @issue %> ]</small></center></p>
<% end %> -</table>
</div>
<div class="box">
@@ -130,9 +125,9 @@ end %> <div class="box">
<h3><%= l(:label_add_note) %></h3>
<%= start_form_tag ({:controller => 'issues', :action => 'add_note', :id => @issue}, :class => "tabular" ) %>
- <p><label for="history_notes"><%=l(:field_notes)%></label>
- <%= text_area 'history', 'notes', :cols => 60, :rows => 10 %></p>
+ <p><label for="notes"><%=l(:field_notes)%></label>
+ <%= text_area_tag 'notes', '', :cols => 60, :rows => 10 %></p>
<%= submit_tag l(:button_add) %>
- <%= end_form_tag %>
+ <%= end_form_tag %>
</div>
<% end %>
diff --git a/redmine/app/views/layouts/base.rhtml b/redmine/app/views/layouts/base.rhtml index e04d3cdea..767f51f61 100644 --- a/redmine/app/views/layouts/base.rhtml +++ b/redmine/app/views/layouts/base.rhtml @@ -133,7 +133,7 @@ var menu_contenu=' \ <div id="footer">
<p>
<%= auto_link $RDM_FOOTER_SIG %> |
- <a href="http://redmine.org/" target="_new"><%= RDM_APP_NAME %></a> <%= RDM_APP_VERSION %>
+ <a href="http://redmine.rubyforge.org/" target="_new"><%= RDM_APP_NAME %></a> <%= RDM_APP_VERSION %>
</p>
</div>
diff --git a/redmine/app/views/mailer/issue_add_note_de.rhtml b/redmine/app/views/mailer/issue_add_note_de.rhtml deleted file mode 100644 index 9942c2440..000000000 --- a/redmine/app/views/mailer/issue_add_note_de.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Note added to issue #<%= @history.issue_id %> by <%= @history.author.name %>
-----------------------------------------
-<%= @history.notes %>
\ No newline at end of file diff --git a/redmine/app/views/mailer/issue_add_note_en.rhtml b/redmine/app/views/mailer/issue_add_note_en.rhtml deleted file mode 100644 index 9942c2440..000000000 --- a/redmine/app/views/mailer/issue_add_note_en.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Note added to issue #<%= @history.issue_id %> by <%= @history.author.name %>
-----------------------------------------
-<%= @history.notes %>
\ No newline at end of file diff --git a/redmine/app/views/mailer/issue_add_note_es.rhtml b/redmine/app/views/mailer/issue_add_note_es.rhtml deleted file mode 100644 index 9942c2440..000000000 --- a/redmine/app/views/mailer/issue_add_note_es.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Note added to issue #<%= @history.issue_id %> by <%= @history.author.name %>
-----------------------------------------
-<%= @history.notes %>
\ No newline at end of file diff --git a/redmine/app/views/mailer/issue_add_note_fr.rhtml b/redmine/app/views/mailer/issue_add_note_fr.rhtml deleted file mode 100644 index 0534cc177..000000000 --- a/redmine/app/views/mailer/issue_add_note_fr.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Note ajoutée à la demande #<%= @history.issue_id %> par <%= @history.author.name %>
-----------------------------------------
-<%= @history.notes %>
\ No newline at end of file diff --git a/redmine/app/views/mailer/issue_change_status_de.rhtml b/redmine/app/views/mailer/issue_change_status_de.rhtml deleted file mode 100644 index e3612ea81..000000000 --- a/redmine/app/views/mailer/issue_change_status_de.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Issue #<%= @issue.id %> has been updated to "<%= @issue.status.name %>" status.
-----------------------------------------
-<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %>
\ No newline at end of file diff --git a/redmine/app/views/mailer/issue_change_status_en.rhtml b/redmine/app/views/mailer/issue_change_status_en.rhtml deleted file mode 100644 index e3612ea81..000000000 --- a/redmine/app/views/mailer/issue_change_status_en.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Issue #<%= @issue.id %> has been updated to "<%= @issue.status.name %>" status.
-----------------------------------------
-<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %>
\ No newline at end of file diff --git a/redmine/app/views/mailer/issue_change_status_es.rhtml b/redmine/app/views/mailer/issue_change_status_es.rhtml deleted file mode 100644 index e3612ea81..000000000 --- a/redmine/app/views/mailer/issue_change_status_es.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Issue #<%= @issue.id %> has been updated to "<%= @issue.status.name %>" status.
-----------------------------------------
-<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %>
\ No newline at end of file diff --git a/redmine/app/views/mailer/issue_change_status_fr.rhtml b/redmine/app/views/mailer/issue_change_status_fr.rhtml deleted file mode 100644 index 831f301d5..000000000 --- a/redmine/app/views/mailer/issue_change_status_fr.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -La demande #<%= @issue.id %> a été mise à jour au statut "<%= @issue.status.name %>".
-----------------------------------------
-<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %>
\ No newline at end of file diff --git a/redmine/app/views/mailer/issue_edit_de.rhtml b/redmine/app/views/mailer/issue_edit_de.rhtml new file mode 100644 index 000000000..1b97a571b --- /dev/null +++ b/redmine/app/views/mailer/issue_edit_de.rhtml @@ -0,0 +1,8 @@ +Issue #<%= @issue.id %> has been updated.
+<%= @journal.user.name %>
+<% for detail in @journal.details %>
+<%= show_detail(detail) %>
+<% end %>
+<%= @journal.notes if @journal.notes? %>
+----------------------------------------
+<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %>
\ No newline at end of file diff --git a/redmine/app/views/mailer/issue_edit_en.rhtml b/redmine/app/views/mailer/issue_edit_en.rhtml new file mode 100644 index 000000000..1b97a571b --- /dev/null +++ b/redmine/app/views/mailer/issue_edit_en.rhtml @@ -0,0 +1,8 @@ +Issue #<%= @issue.id %> has been updated.
+<%= @journal.user.name %>
+<% for detail in @journal.details %>
+<%= show_detail(detail) %>
+<% end %>
+<%= @journal.notes if @journal.notes? %>
+----------------------------------------
+<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %>
\ No newline at end of file diff --git a/redmine/app/views/mailer/issue_edit_es.rhtml b/redmine/app/views/mailer/issue_edit_es.rhtml new file mode 100644 index 000000000..1b97a571b --- /dev/null +++ b/redmine/app/views/mailer/issue_edit_es.rhtml @@ -0,0 +1,8 @@ +Issue #<%= @issue.id %> has been updated.
+<%= @journal.user.name %>
+<% for detail in @journal.details %>
+<%= show_detail(detail) %>
+<% end %>
+<%= @journal.notes if @journal.notes? %>
+----------------------------------------
+<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %>
\ No newline at end of file diff --git a/redmine/app/views/mailer/issue_edit_fr.rhtml b/redmine/app/views/mailer/issue_edit_fr.rhtml new file mode 100644 index 000000000..b7c3a50a3 --- /dev/null +++ b/redmine/app/views/mailer/issue_edit_fr.rhtml @@ -0,0 +1,8 @@ +La demande #<%= @issue.id %> a été mise à jour.
+<%= @journal.user.name %> - <%= format_date(@journal.created_on) %>
+<% for detail in @journal.details %>
+<%= show_detail(detail) %>
+<% end %>
+<%= journal.notes if journal.notes? %>
+----------------------------------------
+<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %>
\ No newline at end of file diff --git a/redmine/db/migrate/007_create_journals.rb b/redmine/db/migrate/007_create_journals.rb new file mode 100644 index 000000000..6170b5bd3 --- /dev/null +++ b/redmine/db/migrate/007_create_journals.rb @@ -0,0 +1,54 @@ +class CreateJournals < ActiveRecord::Migration + + # model removed, but needed for data migration + class IssueHistory < ActiveRecord::Base; belongs_to :issue; end + + def self.up + create_table :journals, :force => true do |t| + t.column "journalized_id", :integer, :default => 0, :null => false + t.column "journalized_type", :string, :limit => 30, :default => "", :null => false + t.column "user_id", :integer, :default => 0, :null => false + t.column "notes", :text + t.column "created_on", :datetime, :null => false + end + create_table :journal_details, :force => true do |t| + t.column "journal_id", :integer, :default => 0, :null => false + t.column "property", :string, :limit => 30, :default => "", :null => false + t.column "prop_key", :string, :limit => 30, :default => "", :null => false + t.column "old_value", :string + t.column "value", :string + end + + # indexes + add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id" + add_index "journal_details", ["journal_id"], :name => "journal_details_journal_id" + + Permission.create :controller => "issues", :action => "history", :description => "label_history", :sort => 1006, :is_public => true, :mail_option => 0, :mail_enabled => 0 + + # data migration + IssueHistory.find(:all, :include => :issue).each {|h| + j = Journal.new(:journalized => h.issue, :user_id => h.author_id, :notes => h.notes, :created_on => h.created_on) + j.details << JournalDetail.new(:property => 'attr', :prop_key => 'status_id', :value => h.status_id) + j.save + } + + drop_table :issue_histories + end + + def self.down + drop_table :journal_details + drop_table :journals + + create_table "issue_histories", :force => true do |t| + t.column "issue_id", :integer, :default => 0, :null => false + t.column "status_id", :integer, :default => 0, :null => false + t.column "author_id", :integer, :default => 0, :null => false + t.column "notes", :text, :default => "" + t.column "created_on", :timestamp + end + + add_index "issue_histories", ["issue_id"], :name => "issue_histories_issue_id" + + Permission.find(:first, :conditions => ["controller=? and action=?", 'issues', 'history']).destroy + end +end diff --git a/redmine/doc/CHANGELOG b/redmine/doc/CHANGELOG index f310f63c3..bbf8a4898 100644 --- a/redmine/doc/CHANGELOG +++ b/redmine/doc/CHANGELOG @@ -7,6 +7,7 @@ http://redmine.org/ == xx/xx/2006 v0.x.x
+* improved issues change history
* new functionality: move an issue to another project or tracker
* new functionality: add a note to an issue
* new report: project activity
diff --git a/redmine/lang/de.yml b/redmine/lang/de.yml index bc10248d8..709ca18da 100644 --- a/redmine/lang/de.yml +++ b/redmine/lang/de.yml @@ -256,6 +256,8 @@ label_calendar: Kalender label_months_from: Monate von
label_gantt_chart: Gantt Diagramm
label_internal: Intern
+label_last_changes: %d änderungen des Letzten
+label_change_view_all: Alle änderungen ansehen
button_login: Einloggen
button_submit: Einreichen
@@ -285,6 +287,9 @@ text_possible_values_info: Werte trennten sich mit | text_project_destroy_confirmation: Sind sie sicher, daß sie das Projekt löschen wollen ?
text_workflow_edit: Auswahl Workflow zum Bearbeiten
text_are_you_sure: Sind sie sicher ?
+text_journal_changed: geändert von %s zu %s
+text_journal_set_to: gestellt zu %s
+text_journal_deleted: gelöscht
default_role_manager: Manager
default_role_developper: Developer
diff --git a/redmine/lang/en.yml b/redmine/lang/en.yml index e30e6c7a0..27cc0260f 100644 --- a/redmine/lang/en.yml +++ b/redmine/lang/en.yml @@ -256,6 +256,8 @@ label_calendar: Calendar label_months_from: months from
label_gantt_chart: Gantt chart
label_internal: Internal
+label_last_changes: last %d changes
+label_change_view_all: View all changes
button_login: Login
button_submit: Submit
@@ -285,6 +287,9 @@ text_possible_values_info: values separated with | text_project_destroy_confirmation: Are you sure you want to delete this project and all related data ?
text_workflow_edit: Select a role and a tracker to edit the workflow
text_are_you_sure: Are you sure ?
+text_journal_changed: changed from %s to %s
+text_journal_set_to: set to %s
+text_journal_deleted: deleted
default_role_manager: Manager
default_role_developper: Developer
diff --git a/redmine/lang/es.yml b/redmine/lang/es.yml index 7c1c6e122..654efd73a 100644 --- a/redmine/lang/es.yml +++ b/redmine/lang/es.yml @@ -256,6 +256,8 @@ label_calendar: Calendario label_months_from: meses de
label_gantt_chart: Diagrama de Gantt
label_internal: Interno
+label_last_changes: %d cambios del último
+label_change_view_all: Ver todos los cambios
button_login: Conexión
button_submit: Someter
@@ -285,6 +287,9 @@ text_possible_values_info: Los valores se separaron con | text_project_destroy_confirmation: ¿ Estás seguro de querer eliminar el proyecto ?
text_workflow_edit: Seleccionar un workflow para actualizar
text_are_you_sure: ¿ Estás seguro ?
+text_journal_changed: cambiado de %s a %s
+text_journal_set_to: fijado a %s
+text_journal_deleted: suprimido
default_role_manager: Manager
default_role_developper: Desarrollador
diff --git a/redmine/lang/fr.yml b/redmine/lang/fr.yml index 5802558ab..5973f1d3a 100644 --- a/redmine/lang/fr.yml +++ b/redmine/lang/fr.yml @@ -257,6 +257,8 @@ label_calendar: Calendrier label_months_from: mois depuis
label_gantt_chart: Diagramme de Gantt
label_internal: Interne
+label_last_changes: %d derniers changements
+label_change_view_all: Voir tous les changements
button_login: Connexion
button_submit: Soumettre
@@ -286,6 +288,9 @@ text_possible_values_info: valeurs séparées par | text_project_destroy_confirmation: Etes-vous sûr de vouloir supprimer ce projet et tout ce qui lui est rattaché ?
text_workflow_edit: Sélectionner un tracker et un rôle pour éditer le workflow
text_are_you_sure: Etes-vous sûr ?
+text_journal_changed: changé de %s à %s
+text_journal_set_to: mis à %s
+text_journal_deleted: supprimé
default_role_manager: Manager
default_role_developper: Développeur
diff --git a/redmine/public/stylesheets/application.css b/redmine/public/stylesheets/application.css index c380b2c3a..bd128a3a7 100644 --- a/redmine/public/stylesheets/application.css +++ b/redmine/public/stylesheets/application.css @@ -186,10 +186,6 @@ form { .noborder {
border:0px;
-Exception exceptions.AssertionError: <exceptions.AssertionError instance at 0xb7c0b20c> in <bound
-method SubversionRepository.__del__ of <vclib.svn.SubversionRepository instance at 0xb7c1252c>>
-ignored
-
background-color:#fff;
width:100%;
}
@@ -292,7 +288,7 @@ table.calenderTable td { border:1px solid #578bb8;
}
-hr { border:none; border-bottom: dotted 2px #c0c0c0; }
+hr { border:none; border-bottom: dotted 1px #c0c0c0; }
/**************** Sidebar styles ****************/
@@ -409,6 +405,17 @@ img.calendar-trigger { margin-left: 4px;
}
+#history h4 {
+ font-size: 1em;
+ margin-bottom: 12px;
+ margin-top: 20px;
+ font-weight: normal;
+ border-bottom: dotted 1px #c0c0c0;
+}
+
+#history p {
+ margin-left: 34px;
+}
/***** CSS FORM ******/
.tabular p{
diff --git a/redmine/test/fixtures/issue_histories.yml b/redmine/test/fixtures/issue_histories.yml deleted file mode 100644 index 5b7803650..000000000 --- a/redmine/test/fixtures/issue_histories.yml +++ /dev/null @@ -1,29 +0,0 @@ ----
-issue_histories_003:
- created_on: 2006-07-19 21:07:27 +02:00
- notes:
- issue_id: 3
- id: 3
- author_id: 2
- status_id: 1
-issue_histories_004:
- created_on: 2006-07-19 21:09:50 +02:00
- notes: Should be bone quickly
- issue_id: 2
- id: 4
- author_id: 2
- status_id: 2
-issue_histories_001:
- created_on: 2006-07-19 21:02:17 +02:00
- notes:
- issue_id: 1
- id: 1
- author_id: 2
- status_id: 1
-issue_histories_002:
- created_on: 2006-07-19 21:04:21 +02:00
- notes:
- issue_id: 2
- id: 2
- author_id: 2
- status_id: 1
|