Project

General

Profile

Feature #1474 » rm1474-note_20_patch_against_trunk_r16111.patch

Mischa The Evil, 2016-12-27 05:12

View differences:

app/helpers/queries_helper.rb (working copy)
183 183
      value ? (value.visible? ? link_to_issue(value, :subject => false) : "##{value.id}") : ''
184 184
    when :description
185 185
      item.description? ? content_tag('div', textilizable(item, :description), :class => "wiki") : ''
186
    when :last_notes
187
      item.last_notes.present? ? content_tag('div', textilizable(item, :last_notes), :class => "wiki") : ''
186 188
    when :done_ratio
187 189
      progress_bar(value)
188 190
    when :relations
app/models/issue.rb (working copy)
244 244
    @spent_hours = nil
245 245
    @total_spent_hours = nil
246 246
    @total_estimated_hours = nil
247
    @last_notes = nil
247 248
    base_reload(*args)
248 249
  end
249 250

  
......
1048 1049
    @relations ||= IssueRelation::Relations.new(self, (relations_from + relations_to).sort)
1049 1050
  end
1050 1051

  
1052
  def last_notes
1053
    if @last_notes
1054
      @last_notes
1055
    else
1056
      notes = self.journals.where.not(notes: '').to_a
1057
      notes.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, self.project)
1058
      notes.last.notes unless notes.empty?
1059
    end
1060
  end
1061

  
1051 1062
  # Preloads relations for a collection of issues
1052 1063
  def self.load_relations(issues)
1053 1064
    if issues.any?
......
1102 1113
    end
1103 1114
  end
1104 1115

  
1116
  # Preloads visible last notes for a collection of issues
1117
  def self.load_visible_last_notes(issues, user=User.current)
1118
    if issues.any?
1119
      issue_ids = issues.map(&:id)
1120

  
1121
      notes = Journal.joins(issue: :project).where.not(notes: '').
1122
        where(:issues => {:id => issue_ids}).order("#{Journal.table_name}.id ASC").to_a
1123

  
1124
      issues.each do |issue|
1125
        note = notes.select{|note| note.journalized_id == issue.id}
1126
        note.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, issue.project)
1127
        issue.instance_variable_set "@last_notes", (note.empty? ? '' : note.last.notes)
1128
      end
1129
    end
1130
  end
1131

  
1105 1132
  # Finds an issue relation given its id.
1106 1133
  def find_relation(relation_id)
1107 1134
    IssueRelation.where("issue_to_id = ? OR issue_from_id = ?", id, id).find(relation_id)
app/models/issue_query.rb (working copy)
44 44
    QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'),
45 45
    QueryColumn.new(:closed_on, :sortable => "#{Issue.table_name}.closed_on", :default_order => 'desc'),
46 46
    QueryColumn.new(:relations, :caption => :label_related_issues),
47
    QueryColumn.new(:description, :inline => false)
47
    QueryColumn.new(:description, :inline => false),
48
    QueryColumn.new(:last_notes, :caption => :label_last_notes, :inline => false)
48 49
  ]
49 50

  
50 51
  def initialize(attributes=nil, *args)
......
330 331
    if has_column?(:relations)
331 332
      Issue.load_visible_relations(issues)
332 333
    end
334
    if has_column?(:last_notes)
335
      Issue.load_visible_last_notes(issues)
336
    end
333 337
    issues
334 338
  rescue ::ActiveRecord::StatementInvalid => e
335 339
    raise StatementInvalid.new(e.message)
app/views/issues/_list.html.erb (working copy)
33 33
  <% @query.block_columns.each do |column|
34 34
       if (text = column_content(column, issue)) && text.present? -%>
35 35
  <tr class="<%= current_cycle %>">
36
    <td colspan="<%= @query.inline_columns.size + 1 %>" class="<%= column.css_classes %>"><%= text %></td>
36
    <td colspan="<%= @query.inline_columns.size + 1 %>" class="<%= column.css_classes %>">
37
      <% if query.block_columns.count > 1 %>
38
        <span><%= column.caption %></span>
39
      <% end %>
40
      <%= text %>
41
    </td>
37 42
  </tr>
38 43
  <% end -%>
39 44
  <% end -%>
app/views/issues/index.html.erb (working copy)
37 37
  </p>
38 38
  <p>
39 39
    <label><%= check_box_tag 'csv[description]', '1', @query.has_column?(:description) %> <%= l(:field_description) %></label>
40
    <label><%= check_box_tag 'csv[last_notes]', '1', @query.has_column?(:last_notes) %> <%= l(:label_last_notes) %></label>
40 41
  </p>
41 42
  <% if @issue_count > Setting.issues_export_limit.to_i %>
42 43
  <p class="icon icon-warning">
app/views/timelog/_list.html.erb (working copy)
50 50
  <% @query.block_columns.each do |column|
51 51
       if (text = column_content(column, issue)) && text.present? -%>
52 52
  <tr class="<%= current_cycle %>">
53
    <td colspan="<%= @query.inline_columns.size + 1 %>" class="<%= column.css_classes %>"><%= text %></td>
53
    <td colspan="<%= @query.inline_columns.size + 1 %>" class="<%= column.css_classes %>">
54
    <% if query.block_columns.count > 1 %>
55
      <span><%= column.caption %></span>
56
    <% end %>
57
    <%= text %>
58
    </td>
54 59
  </tr>
55 60
  <% end -%>
56 61
  <% end -%>
config/locales/en.yml (working copy)
1009 1009
  label_font_default: Default font
1010 1010
  label_font_monospace: Monospaced font
1011 1011
  label_font_proportional: Proportional font
1012
  label_last_notes: Last notes
1012 1013

  
1013 1014
  button_login: Login
1014 1015
  button_submit: Submit
lib/redmine/export/pdf/issues_pdf_helper.rb (working copy)
266 266
            table_width = col_width.inject(0, :+)
267 267
          end
268 268
  
269
          # use full width if the description is displayed
270
          if table_width > 0 && query.has_column?(:description)
269
          # use full width if the description or last_notes are displayed
270
          if table_width > 0 && (query.has_column?(:description) || query.has_column?(:last_notes))
271 271
            col_width = col_width.map {|w| w * (page_width - right_margin - left_margin) / table_width}
272 272
            table_width = col_width.inject(0, :+)
273 273
          end
......
327 327
              pdf.RDMwriteHTMLCell(0, 5, 10, '', issue.description.to_s, issue.attachments, "LRBT")
328 328
              pdf.set_auto_page_break(false)
329 329
            end
330

  
331
            if query.has_column?(:last_notes) && issue.last_notes.present?
332
              pdf.set_x(10)
333
              pdf.set_auto_page_break(true, bottom_margin)
334
              pdf.RDMwriteHTMLCell(0, 5, 10, '', issue.last_notes.to_s, [], "LRBT")
335
              pdf.set_auto_page_break(false)
330 336
          end
337
          end
331 338
  
332 339
          if issues.size == Setting.issues_export_limit.to_i
333 340
            pdf.SetFontStyle('B',10)
public/stylesheets/application.css (working copy)
255 255
tr.issue td.relations { text-align: left; }
256 256
tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
257 257
tr.issue td.relations span {white-space: nowrap;}
258
table.issues td.description {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;}
259
table.issues td.description pre {white-space:normal;}
258
table.issues td.description, table.issues td.last_notes {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;}
259
table.issues td.description pre, table.issues td.last_notes pre {white-space:normal;}
260 260

  
261 261
tr.issue.idnt td.subject {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%;}
262 262
tr.issue.idnt-1 td.subject {padding-left: 24px; background-position: 8px 50%;}
test/functional/issues_controller_test.rb (working copy)
959 959
    assert_equal 'application/pdf', response.content_type
960 960
  end
961 961

  
962
  def test_index_with_last_notes_column
963
    get :index, :set_filter => 1, :c => %w(subject last_notes)
964

  
965
    assert_response :success
966
    assert_select 'table.issues thead th', 3 # columns: chekbox + id + subject
967

  
968
    assert_select 'td.last_notes[colspan="3"]', :text => 'Some notes with Redmine links: #2, r2.'
969
    assert_select 'td.last_notes[colspan="3"]', :text => 'A comment with inline image:  and a reference to #1 and r2.'
970

  
971
    get :index, :set_filter => 1, :c => %w(subject last_notes), :format => 'pdf'
972
    assert_response :success
973
    assert_equal 'application/pdf', response.content_type
974
  end
975

  
976
  def test_index_with_last_notes_column_should_display_private_notes_with_permission_only
977
    journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true, :user_id => 1)
978
    @request.session[:user_id] = 2
979

  
980
    get :index, :set_filter => 1, :c => %w(subject last_notes)
981
    assert_response :success
982
    assert_select 'td.last_notes[colspan="3"]', :text => 'Privates notes'
983

  
984
    Role.find(1).remove_permission! :view_private_notes
985

  
986
    get :index, :set_filter => 1, :c => %w(subject last_notes)
987
    assert_response :success
988
    assert_select 'td.last_notes[colspan="3"]', :text => 'A comment with inline image:  and a reference to #1 and r2.'
989
  end
990

  
991
  def test_index_with_description_and_last_notes_columns_should_display_column_name
992
    get :index, :set_filter => 1, :c => %w(subject last_notes description)
993
    assert_response :success
994

  
995
    assert_select 'td.last_notes[colspan="3"] span', :text => 'Last notes'
996
    assert_select 'td.description[colspan="3"] span', :text => 'Description'
997
  end
998

  
962 999
  def test_index_with_parent_column
963 1000
    Issue.delete_all
964 1001
    parent = Issue.generate!
test/unit/query_test.rb (working copy)
1107 1107

  
1108 1108
  def test_inline_and_block_columns
1109 1109
    q = IssueQuery.new
1110
    q.column_names = ['subject', 'description', 'tracker']
1110
    q.column_names = ['subject', 'description', 'tracker', 'last_notes']
1111 1111

  
1112 1112
    assert_equal [:id, :subject, :tracker], q.inline_columns.map(&:name)
1113
    assert_equal [:description], q.block_columns.map(&:name)
1113
    assert_equal [:description, :last_notes], q.block_columns.map(&:name)
1114 1114
  end
1115 1115

  
1116 1116
  def test_custom_field_columns_should_be_inline
......
1127 1127
    assert_not_nil issues.first.instance_variable_get("@spent_hours")
1128 1128
  end
1129 1129

  
1130
  def test_query_should_preload_last_notes
1131
    q = IssueQuery.new(:name => '_', :column_names => [:subject, :last_notes])
1132
    assert q.has_column?(:last_notes)
1133
    issues = q.issues
1134
    assert_not_nil issues.first.instance_variable_get("@last_notes")
1135
  end
1136

  
1130 1137
  def test_groupable_columns_should_include_custom_fields
1131 1138
    q = IssueQuery.new
1132 1139
    column = q.groupable_columns.detect {|c| c.name == :cf_1}
(8-8/11)