Project

General

Profile

Feature #1474 » rm1474-note_20_patch_against_trunk_r16233.patch

Marius BĂLTEANU, 2017-01-20 11:43

View differences:

app/helpers/queries_helper.rb
185 185
      value ? (value.visible? ? link_to_issue(value, :subject => false) : "##{value.id}") : ''
186 186
    when :description
187 187
      item.description? ? content_tag('div', textilizable(item, :description), :class => "wiki") : ''
188
    when :last_notes
189
      item.last_notes.present? ? content_tag('div', textilizable(item, :last_notes), :class => "wiki") : ''
188 190
    when :done_ratio
189 191
      progress_bar(value)
190 192
    when :relations
app/models/issue.rb
239 239
    @spent_hours = nil
240 240
    @total_spent_hours = nil
241 241
    @total_estimated_hours = nil
242
    @last_notes = nil
242 243
    base_reload(*args)
243 244
  end
244 245

  
......
1063 1064
    @relations ||= IssueRelation::Relations.new(self, (relations_from + relations_to).sort)
1064 1065
  end
1065 1066

  
1067
  def last_notes
1068
    if @last_notes
1069
      @last_notes
1070
    else
1071
      notes = self.journals.visible.where.not(notes: '').to_a
1072
      notes.last.notes unless notes.empty?
1073
    end
1074
  end
1075

  
1066 1076
  # Preloads relations for a collection of issues
1067 1077
  def self.load_relations(issues)
1068 1078
    if issues.any?
......
1126 1136
      where(:ancestors => {:id => issues.map(&:id)})
1127 1137
  end
1128 1138

  
1139
  # Preloads visible last notes for a collection of issues
1140
  def self.load_visible_last_notes(issues, user=User.current)
1141
    if issues.any?
1142
      issue_ids = issues.map(&:id)
1143

  
1144
      notes = Journal.joins(issue: :project).where.not(notes: '').
1145
        where(Journal.visible_notes_condition(User.current, :skip_pre_condition => true)).
1146
        where(:issues => {:id => issue_ids}).order("#{Journal.table_name}.id ASC").to_a
1147

  
1148
      issues.each do |issue|
1149
        note = notes.select{|note| note.journalized_id == issue.id}
1150
        issue.instance_variable_set "@last_notes", (note.empty? ? '' : note.last.notes)
1151
      end
1152
    end
1153
  end
1154

  
1129 1155
  # Finds an issue relation given its id.
1130 1156
  def find_relation(relation_id)
1131 1157
    IssueRelation.where("issue_to_id = ? OR issue_from_id = ?", id, id).find(relation_id)
app/models/issue_query.rb
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)
......
297 298
    if has_column?(:relations)
298 299
      Issue.load_visible_relations(issues)
299 300
    end
301
    if has_column?(:last_notes)
302
      Issue.load_visible_last_notes(issues)
303
    end
300 304
    issues
301 305
  rescue ::ActiveRecord::StatementInvalid => e
302 306
    raise StatementInvalid.new(e.message)
app/views/issues/_list.html.erb
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
37 37
  </p>
38 38
  <p>
39 39
    <label><%= check_box_tag 'c[]', 'description', @query.has_column?(:description) %> <%= l(:field_description) %></label>
40
    <label><%= check_box_tag 'c[]', 'last_notes', @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
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
1015 1015
  label_font_default: Default font
1016 1016
  label_font_monospace: Monospaced font
1017 1017
  label_font_proportional: Proportional font
1018
  label_last_notes: Last notes
1018 1019

  
1019 1020
  button_login: Login
1020 1021
  button_submit: Submit
lib/redmine/export/pdf/issues_pdf_helper.rb
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)
336
          end
330 337
          end
331 338
  
332 339
          if issues.size == Setting.issues_export_limit.to_i
public/stylesheets/application.css
258 258
tr.issue td.relations { text-align: left; }
259 259
tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
260 260
tr.issue td.relations span {white-space: nowrap;}
261
table.issues td.description {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;}
262
table.issues td.description pre {white-space:normal;}
261
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;}
262
table.issues td.description pre, table.issues td.last_notes pre {white-space:normal;}
263 263

  
264 264
tr.issue.idnt td.subject {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%;}
265 265
tr.issue.idnt-1 td.subject {padding-left: 24px; background-position: 8px 50%;}
test/functional/issues_controller_test.rb
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
1267 1267

  
1268 1268
  def test_inline_and_block_columns
1269 1269
    q = IssueQuery.new
1270
    q.column_names = ['subject', 'description', 'tracker']
1270
    q.column_names = ['subject', 'description', 'tracker', 'last_notes']
1271 1271

  
1272 1272
    assert_equal [:id, :subject, :tracker], q.inline_columns.map(&:name)
1273
    assert_equal [:description], q.block_columns.map(&:name)
1273
    assert_equal [:description, :last_notes], q.block_columns.map(&:name)
1274 1274
  end
1275 1275

  
1276 1276
  def test_custom_field_columns_should_be_inline
......
1287 1287
    assert_not_nil issues.first.instance_variable_get("@spent_hours")
1288 1288
  end
1289 1289

  
1290
  def test_query_should_preload_last_notes
1291
    q = IssueQuery.new(:name => '_', :column_names => [:subject, :last_notes])
1292
    assert q.has_column?(:last_notes)
1293
    issues = q.issues
1294
    assert_not_nil issues.first.instance_variable_get("@last_notes")
1295
  end
1296

  
1290 1297
  def test_groupable_columns_should_include_custom_fields
1291 1298
    q = IssueQuery.new
1292 1299
    column = q.groupable_columns.detect {|c| c.name == :cf_1}
(9-9/11)