]> source.dussan.org Git - redmine.git/commitdiff
Adds a Reply link to each issue note (#739). Reply is pre-filled with the quoted...
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Fri, 30 May 2008 17:42:25 +0000 (17:42 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Fri, 30 May 2008 17:42:25 +0000 (17:42 +0000)
git-svn-id: http://redmine.rubyforge.org/svn/trunk@1480 e93f8b46-1217-0410-a6f0-8f06a7374b81

34 files changed:
app/controllers/issues_controller.rb
app/helpers/journals_helper.rb
app/views/issues/_history.rhtml
app/views/issues/show.rhtml
lang/bg.yml
lang/cs.yml
lang/da.yml
lang/de.yml
lang/en.yml
lang/es.yml
lang/fi.yml
lang/fr.yml
lang/he.yml
lang/hu.yml
lang/it.yml
lang/ja.yml
lang/ko.yml
lang/lt.yml
lang/nl.yml
lang/no.yml
lang/pl.yml
lang/pt-br.yml
lang/pt.yml
lang/ro.yml
lang/ru.yml
lang/sr.yml
lang/sv.yml
lang/th.yml
lang/uk.yml
lang/zh-tw.yml
lang/zh.yml
lib/redmine.rb
public/images/comment.png [new file with mode: 0644]
test/functional/issues_controller_test.rb

index ca3309c4694273c77c9dc0c6296156b64b419025..defc0a11ee2842b28c1a0f073143069fb32cf3ad 100644 (file)
@@ -19,7 +19,7 @@ class IssuesController < ApplicationController
   layout 'base'
   menu_item :new_issue, :only => :new
   
-  before_filter :find_issue, :only => [:show, :edit, :destroy_attachment]
+  before_filter :find_issue, :only => [:show, :edit, :reply, :destroy_attachment]
   before_filter :find_issues, :only => [:bulk_edit, :move, :destroy]
   before_filter :find_project, :only => [:new, :update_form, :preview]
   before_filter :authorize, :except => [:index, :changes, :preview, :update_form, :context_menu]
@@ -208,6 +208,26 @@ class IssuesController < ApplicationController
     flash.now[:error] = l(:notice_locking_conflict)
   end
 
+  def reply
+    journal = Journal.find(params[:journal_id]) if params[:journal_id]
+    if journal
+      user = journal.user
+      text = journal.notes
+    else
+      user = @issue.author
+      text = @issue.description
+    end
+    content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> "
+    content << text.to_s.strip.gsub(%r{<pre>((.|\s)*?)</pre>}m, '[...]').gsub("\n", "\n> ") + "\n\n"
+    render(:update) { |page|
+      page.replace_html "notes", content
+      page.show 'update'
+      page << "Form.Element.focus('notes');"
+      page << "Element.scrollTo('update');"
+      page << "$('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight;"
+    }
+  end
+  
   # Bulk edit a set of issues
   def bulk_edit
     if request.post?
index 234bfabc04841581e4d4944955a094ef180ba7bc..92d6e55932355b79a3493a7a70ce22bde66d75d1 100644 (file)
@@ -19,13 +19,16 @@ module JournalsHelper
   def render_notes(journal, options={})
     content = ''
     editable = journal.editable_by?(User.current)
-    if editable && !journal.notes.blank?
-      links = []
+    links = []
+    if !journal.notes.blank?
       links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes", 
                                              { :controller => 'journals', :action => 'edit', :id => journal },
-                                                :title => l(:button_edit))
-      content << content_tag('div', links.join(' '), :class => 'contextual')
+                                                :title => l(:button_edit)) if editable
+      links << link_to_remote(image_tag('comment.png'),
+                              { :url => {:controller => 'issues', :action => 'reply', :id => journal.journalized, :journal_id => journal} },
+                              :title => l(:button_reply)) if options[:reply_links]
     end
+    content << content_tag('div', links.join(' '), :class => 'contextual') unless links.empty?
     content << textilizable(journal, :notes)
     content_tag('div', content, :id => "journal-#{journal.id}-notes", :class => (editable ? 'wiki editable' : 'wiki'))
   end
index f29a44daf4631d4b33585b390a65b570c200c92e..b8efdb400c4f61554ee5f935d622086d3c7662e2 100644 (file)
@@ -1,3 +1,4 @@
+<% reply_links = authorize_for('issues', 'edit') -%>
 <% for journal in journals %>
     <div id="change-<%= journal.id %>" class="journal">
        <h4><div style="float:right;"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div>
@@ -8,6 +9,6 @@
           <li><%= show_detail(detail) %></li>
        <% end %>
        </ul>
-       <%= render_notes(journal) unless journal.notes.blank? %>
+       <%= render_notes(journal, :reply_links => reply_links) unless journal.notes.blank? %>
        </div>
 <% end %>
index f788d0ec8cbbc732d3ca579e4c6056b09e0db467..f1c8a82cda0ce595d377c3bcd205656a25cfaed0 100644 (file)
@@ -56,6 +56,12 @@ end %>
 </table>
 <hr />
 
+<div class="contextual">
+<%= link_to_remote(image_tag('comment.png'),
+                   { :url => {:controller => 'issues', :action => 'reply', :id => @issue} },
+                   :title => l(:button_reply)) if authorize_for('issues', 'edit') %>
+</div>
+                              
 <p><strong><%=l(:field_description)%></strong></p>
 <div class="wiki">
 <%= textilizable @issue, :description, :attachments => @issue.attachments %>
index 10198bce9df7358e660f5afc7ce9a0ceabfa1e50..05a0b0d600a251a1b08b8d0fa70961a46bde2e3e 100644 (file)
@@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index f90068b3b05177cf29f2247c24aa58c13cd23c1f..829f4449ef9703f191b374d6c058c560a1b8fcce 100644 (file)
@@ -626,3 +626,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index ca4ddeb468fa3220fdd42bb19817c919a56405e5..92df87e3f9aec7691fc0098f29c2937f9beed8b3 100644 (file)
@@ -623,3 +623,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index fa33e1c7422c56e134bef7a80623ede17fe14e41..1351d1944e058417662c47b3b4b2f76e30b4c320 100644 (file)
@@ -622,3 +622,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index f9e07d211aa86092377c1dae8a1fa00cffec91ad..4184a917577275032e6d03fb3dfb3afba695a533 100644 (file)
@@ -596,6 +596,7 @@ text_destroy_time_entries_question: %.02f hours were reported on the issues you
 text_destroy_time_entries: Delete reported hours
 text_assign_time_entries_to_project: Assign reported hours to the project
 text_reassign_time_entries: 'Reassign reported hours to this issue:'
+text_user_wrote: '%s wrote:'
 
 default_role_manager: Manager
 default_role_developper: Developer
index 3d8c0a931f88c6ab483a9188fad8225ed07b9a59..ea479630dd72b954e87afb0ebfb3b7f74b313da2 100644 (file)
@@ -624,3 +624,4 @@ text_subprojects_destroy_warning: 'Sus subprojectos: %s también se eliminarán'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 60428bb4976568341988c08e8dc63dfd7b559cc1..b3b88862236e23edcd4daccbd44aa7bcc6c6ad43 100644 (file)
@@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Tämän alaprojekti(t): %s tullaan myös pois
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 8b002bbf6c602de0db2910a78d57579a641e27c5..a802a44cc9bde4be1c9fd5cfd1a53656b2bbf988 100644 (file)
@@ -596,6 +596,7 @@ text_destroy_time_entries_question: %.02f heures ont été enregistrées sur les
 text_destroy_time_entries: Supprimer les heures
 text_assign_time_entries_to_project: Reporter les heures sur le projet
 text_reassign_time_entries: 'Reporter les heures sur cette demande:'
+text_user_wrote: '%s a écrit:'
 
 default_role_manager: Manager
 default_role_developper: Développeur
index f972ef62a64167542ae64e2dc6089959f80822a2..c4d69ebb956121bf8f564d3f7e46b6ac00618de9 100644 (file)
@@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index f6d312ce0f0e1983cb92c519095eab6e67d7202b..fd7bf9f52a0a0b8def061db9a9adc86f8c2d9eeb 100644 (file)
@@ -622,3 +622,4 @@ enumeration_doc_categories: Dokumentum kategóriák
 enumeration_activities: Tevékenységek (idő rögzítés)
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index a8646644aeb3395363b31d20dae2978a7c363328..519dcd01fbce33625a95020d6990713889032b2b 100644 (file)
@@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index d119cf55e0801eef2cd88d128b62dbdea9073d05..714539c7d79ad3560519f8193f57fdd953f29a13 100644 (file)
@@ -622,3 +622,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 98dde9e0634846352300cbfb59c30fe6f81f6734..81656040cdce2c7a9fbd7d31a1ac001b13054951 100644 (file)
@@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 6b791d87b250085d8695226652ec2a28e8aa2a17..89e607a83756bd7abf2c630617295375efaec186 100644 (file)
@@ -623,3 +623,4 @@ label_and_its_subprojects: %s projektas ir jo subprojektai
 
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index c36eaecd572611e3d8f53e57d691af6183cae8d2..eebc7d993f0a334f1fe914346459d784a7549214 100644 (file)
@@ -622,3 +622,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 5e788dc502df01f6e06fc31ac9e717e266ac78ff..3f6ef6dede44d5cb4b17f17e1d2c24dd808b4494 100644 (file)
@@ -622,3 +622,4 @@ enumeration_doc_categories: Dokument-kategorier
 enumeration_activities: Aktiviteter (tidssporing)
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 4476c2160227c95a2983a9a5144dd161796ad75d..81a7a0dbaa93d0cd9b6bf26ca18fbee7489080d8 100644 (file)
@@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 9b3d231516190f168e1078fd6daf752f617513f0..47e80a14442238a6fbda6efdae54f0cba47cac4b 100644 (file)
@@ -621,3 +621,4 @@ label_age: Age
 label_and_its_subprojects: %s and its subprojects\r
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"\r
 mail_subject_reminder: "%d issue(s) due in the next days"\r
+text_user_wrote: '%s wrote:'\r
index c56b76a0b7b351153d070a6455e1aa2a81b9612c..002a1b7f87d57d34e4a286b3b37a8e1b88909e85 100644 (file)
@@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 30464569b3d1342efe213820802d86d650bd9428..6bcd55a50dfe3e736e47a21fe004ec0bd0b54ed7 100644 (file)
@@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index f4fd920375eac349d0aaf441c92a55f2642b4430..fa8fd69a99214cf066400a1515881ccc3f2ccb39 100644 (file)
@@ -625,3 +625,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 53e4f9f2c2235e2704f18cbf440264b737fe2dd4..9a4adf2141e9dcb27d1bf405719d4757f8b496ff 100644 (file)
@@ -622,3 +622,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 248f3dcba0215a06e49320cf2f6ff1fae2a62c02..1ab11e98b05b80339c6e367f6116b14045ecd942 100644 (file)
@@ -622,3 +622,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 444316aa156b24b0042fc1f9a263bb9ad5e7c808..751aac749a7f968a8405fa04bcf3914004c201c3 100644 (file)
@@ -624,3 +624,4 @@ enumeration_activities: กิจกรรม (ใช้ในการติด
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 3cc60ef48377117b09bed8e21b6fb4b63fb9e05a..3ab4462ed4654c36abbb29546367a2661548b100 100644 (file)
@@ -623,3 +623,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
 label_and_its_subprojects: %s and its subprojects
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 3926113b2b935f359620c044cb0bc8a7c03d5563..3b7808aae6d71274a62281351d783ce37fb78827 100644 (file)
@@ -622,3 +622,4 @@ enumeration_doc_categories: 文件分類
 enumeration_activities: 活動 (時間追蹤)
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
 mail_subject_reminder: "%d issue(s) due in the next days"
+text_user_wrote: '%s wrote:'
index 55516e0331c5891b0a1abfca816c9f1096396cbb..b5ecace824f3914b0cf95797c4194e266738febb 100644 (file)
@@ -622,3 +622,4 @@ enumeration_doc_categories: 文档类别
 enumeration_activities: 活动(时间跟踪)
 mail_subject_reminder: "%d issue(s) due in the next days"
 mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:"
+text_user_wrote: '%s wrote:'
index b21f5716dbeee5a0bb6cc31764d991fa5cf75d77..7b9832d62ed85c6f68ea833a73c369dfe0d3829b 100644 (file)
@@ -32,9 +32,9 @@ Redmine::AccessControl.map do |map|
                                   :queries => :index,
                                   :reports => :issue_report}, :public => true                    
     map.permission :add_issues, {:issues => :new}
-    map.permission :edit_issues, {:issues => [:edit, :bulk_edit, :destroy_attachment]}
+    map.permission :edit_issues, {:issues => [:edit, :reply, :bulk_edit, :destroy_attachment]}
     map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
-    map.permission :add_issue_notes, {:issues => :edit}
+    map.permission :add_issue_notes, {:issues => [:edit, :reply]}
     map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
     map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
     map.permission :move_issues, {:issues => :move}, :require => :loggedin
diff --git a/public/images/comment.png b/public/images/comment.png
new file mode 100644 (file)
index 0000000..7bc9233
Binary files /dev/null and b/public/images/comment.png differ
index c4389fedd54d32e61d5b684e3d8fc20571e2027b..7c7d44e5f5b33311fa54b908c61254517e93fe86 100644 (file)
@@ -263,6 +263,22 @@ class IssuesControllerTest < Test::Unit::TestCase
                                     :content => 'Urgent',
                                     :attributes => { :selected => 'selected' } }
   end
+  
+  def test_reply_to_issue
+    @request.session[:user_id] = 2
+    get :reply, :id => 1
+    assert_response :success
+    assert_select_rjs :show, "update"
+    assert_select_rjs :replace_html, "notes"
+  end
+
+  def test_reply_to_note
+    @request.session[:user_id] = 2
+    get :reply, :id => 1, :journal_id => 2
+    assert_response :success
+    assert_select_rjs :show, "update"
+    assert_select_rjs :replace_html, "notes"
+  end
 
   def test_post_edit
     @request.session[:user_id] = 2