Feature #1474 » add_last_notes_column_v3.diff
| app/helpers/queries_helper.rb | ||
|---|---|---|
| 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 | ||
|---|---|---|
| 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 | ||
|---|---|---|
| 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 | ||
|---|---|---|
| 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 '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 | ||
|---|---|---|
| 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 | ||
|---|---|---|
| 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 | ||
|---|---|---|
| 45 | 45 |
pdf.SetFontStyle('',8)
|
| 46 | 46 |
pdf.RDMMultiCell(190, 5, "#{format_time(issue.created_on)} - #{issue.author}")
|
| 47 | 47 |
pdf.ln |
| 48 |
|
|
| 48 | ||
| 49 | 49 |
left = [] |
| 50 | 50 |
left << [l(:field_status), issue.status] |
| 51 | 51 |
left << [l(:field_priority), issue.priority] |
| 52 | 52 |
left << [l(:field_assigned_to), issue.assigned_to] unless issue.disabled_core_fields.include?('assigned_to_id')
|
| 53 | 53 |
left << [l(:field_category), issue.category] unless issue.disabled_core_fields.include?('category_id')
|
| 54 | 54 |
left << [l(:field_fixed_version), issue.fixed_version] unless issue.disabled_core_fields.include?('fixed_version_id')
|
| 55 |
|
|
| 55 | ||
| 56 | 56 |
right = [] |
| 57 | 57 |
right << [l(:field_start_date), format_date(issue.start_date)] unless issue.disabled_core_fields.include?('start_date')
|
| 58 | 58 |
right << [l(:field_due_date), format_date(issue.due_date)] unless issue.disabled_core_fields.include?('due_date')
|
| 59 | 59 |
right << [l(:field_done_ratio), "#{issue.done_ratio}%"] unless issue.disabled_core_fields.include?('done_ratio')
|
| 60 | 60 |
right << [l(:field_estimated_hours), l_hours(issue.estimated_hours)] unless issue.disabled_core_fields.include?('estimated_hours')
|
| 61 | 61 |
right << [l(:label_spent_time), l_hours(issue.total_spent_hours)] if User.current.allowed_to?(:view_time_entries, issue.project) |
| 62 |
|
|
| 62 | ||
| 63 | 63 |
rows = left.size > right.size ? left.size : right.size |
| 64 | 64 |
while left.size < rows |
| 65 | 65 |
left << nil |
| ... | ... | |
| 67 | 67 |
while right.size < rows |
| 68 | 68 |
right << nil |
| 69 | 69 |
end |
| 70 |
|
|
| 70 | ||
| 71 | 71 |
half = (issue.visible_custom_field_values.size / 2.0).ceil |
| 72 | 72 |
issue.visible_custom_field_values.each_with_index do |custom_value, i| |
| 73 | 73 |
(i < half ? left : right) << [custom_value.custom_field.name, show_value(custom_value, false)] |
| 74 | 74 |
end |
| 75 |
|
|
| 75 | ||
| 76 | 76 |
if pdf.get_rtl |
| 77 | 77 |
border_first_top = 'RT' |
| 78 | 78 |
border_last_top = 'LT' |
| ... | ... | |
| 84 | 84 |
border_first = 'L' |
| 85 | 85 |
border_last = 'R' |
| 86 | 86 |
end |
| 87 |
|
|
| 87 | ||
| 88 | 88 |
rows = left.size > right.size ? left.size : right.size |
| 89 | 89 |
rows.times do |i| |
| 90 | 90 |
heights = [] |
| ... | ... | |
| 99 | 99 |
item = right[i] |
| 100 | 100 |
heights << pdf.get_string_height(60, item ? item.last.to_s : "") |
| 101 | 101 |
height = heights.max |
| 102 |
|
|
| 102 | ||
| 103 | 103 |
item = left[i] |
| 104 | 104 |
pdf.SetFontStyle('B',9)
|
| 105 | 105 |
pdf.RDMMultiCell(35, height, item ? "#{item.first}:" : "", (i == 0 ? border_first_top : border_first), '', 0, 0)
|
| 106 | 106 |
pdf.SetFontStyle('',9)
|
| 107 | 107 |
pdf.RDMMultiCell(60, height, item ? item.last.to_s : "", (i == 0 ? border_last_top : border_last), '', 0, 0) |
| 108 |
|
|
| 108 | ||
| 109 | 109 |
item = right[i] |
| 110 | 110 |
pdf.SetFontStyle('B',9)
|
| 111 | 111 |
pdf.RDMMultiCell(35, height, item ? "#{item.first}:" : "", (i == 0 ? border_first_top : border_first), '', 0, 0)
|
| 112 | 112 |
pdf.SetFontStyle('',9)
|
| 113 | 113 |
pdf.RDMMultiCell(60, height, item ? item.last.to_s : "", (i == 0 ? border_last_top : border_last), '', 0, 2) |
| 114 |
|
|
| 114 | ||
| 115 | 115 |
pdf.set_x(base_x) |
| 116 | 116 |
end |
| 117 |
|
|
| 117 | ||
| 118 | 118 |
pdf.SetFontStyle('B',9)
|
| 119 | 119 |
pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1) |
| 120 | 120 |
pdf.SetFontStyle('',9)
|
| 121 |
|
|
| 121 | ||
| 122 | 122 |
# Set resize image scale |
| 123 | 123 |
pdf.set_image_scale(1.6) |
| 124 | 124 |
text = textilizable(issue, :description, |
| ... | ... | |
| 128 | 128 |
:inline_attachments => false |
| 129 | 129 |
) |
| 130 | 130 |
pdf.RDMwriteFormattedCell(35+155, 5, '', '', text, issue.attachments, "LRB") |
| 131 |
|
|
| 131 | ||
| 132 | 132 |
unless issue.leaf? |
| 133 | 133 |
truncate_length = (!is_cjk? ? 90 : 65) |
| 134 | 134 |
pdf.SetFontStyle('B',9)
|
| ... | ... | |
| 145 | 145 |
pdf.ln |
| 146 | 146 |
end |
| 147 | 147 |
end |
| 148 |
|
|
| 148 | ||
| 149 | 149 |
relations = issue.relations.select { |r| r.other_issue(issue).visible? }
|
| 150 | 150 |
unless relations.empty? |
| 151 | 151 |
truncate_length = (!is_cjk? ? 80 : 60) |
| ... | ... | |
| 173 | 173 |
end |
| 174 | 174 |
pdf.RDMCell(190,5, "", "T") |
| 175 | 175 |
pdf.ln |
| 176 |
|
|
| 176 | ||
| 177 | 177 |
if issue.changesets.any? && |
| 178 | 178 |
User.current.allowed_to?(:view_changesets, issue.project) |
| 179 | 179 |
pdf.SetFontStyle('B',9)
|
| ... | ... | |
| 193 | 193 |
pdf.ln |
| 194 | 194 |
end |
| 195 | 195 |
end |
| 196 |
|
|
| 196 | ||
| 197 | 197 |
if assoc[:journals].present? |
| 198 | 198 |
pdf.SetFontStyle('B',9)
|
| 199 | 199 |
pdf.RDMCell(190,5, l(:label_history), "B") |
| ... | ... | |
| 222 | 222 |
pdf.ln |
| 223 | 223 |
end |
| 224 | 224 |
end |
| 225 |
|
|
| 225 | ||
| 226 | 226 |
if issue.attachments.any? |
| 227 | 227 |
pdf.SetFontStyle('B',9)
|
| 228 | 228 |
pdf.RDMCell(190,5, l(:label_attachment_plural), "B") |
| ... | ... | |
| 249 | 249 |
pdf.footer_date = format_date(User.current.today) |
| 250 | 250 |
pdf.set_auto_page_break(false) |
| 251 | 251 |
pdf.add_page("L")
|
| 252 |
|
|
| 252 | ||
| 253 | 253 |
# Landscape A4 = 210 x 297 mm |
| 254 | 254 |
page_height = pdf.get_page_height # 210 |
| 255 | 255 |
page_width = pdf.get_page_width # 297 |
| ... | ... | |
| 257 | 257 |
right_margin = pdf.get_original_margins['right'] # 10 |
| 258 | 258 |
bottom_margin = pdf.get_footer_margin |
| 259 | 259 |
row_height = 4 |
| 260 |
|
|
| 260 | ||
| 261 | 261 |
# column widths |
| 262 | 262 |
table_width = page_width - right_margin - left_margin |
| 263 | 263 |
col_width = [] |
| ... | ... | |
| 265 | 265 |
col_width = calc_col_width(issues, query, table_width, pdf) |
| 266 | 266 |
table_width = col_width.inject(0, :+) |
| 267 | 267 |
end |
| 268 |
|
|
| 269 |
# use full width if the description is displayed
|
|
| 270 |
if table_width > 0 && query.has_column?(:description)
|
|
| 268 | ||
| 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 |
| 274 |
|
|
| 274 | ||
| 275 | 275 |
# title |
| 276 | 276 |
pdf.SetFontStyle('B',11)
|
| 277 | 277 |
pdf.RDMCell(190, 8, title) |
| ... | ... | |
| 303 | 303 |
end |
| 304 | 304 |
previous_group = group |
| 305 | 305 |
end |
| 306 |
|
|
| 306 | ||
| 307 | 307 |
# fetch row values |
| 308 | 308 |
col_values = fetch_row_values(issue, query, level) |
| 309 |
|
|
| 309 | ||
| 310 | 310 |
# make new page if it doesn't fit on the current one |
| 311 | 311 |
base_y = pdf.get_y |
| 312 | 312 |
max_height = get_issues_to_pdf_write_cells(pdf, col_values, col_width) |
| ... | ... | |
| 316 | 316 |
render_table_header(pdf, query, col_width, row_height, table_width) |
| 317 | 317 |
base_y = pdf.get_y |
| 318 | 318 |
end |
| 319 |
|
|
| 319 | ||
| 320 | 320 |
# write the cells on page |
| 321 | 321 |
issues_to_pdf_write_cells(pdf, col_values, col_width, max_height) |
| 322 | 322 |
pdf.set_y(base_y + max_height) |
| 323 |
|
|
| 323 | ||
| 324 | 324 |
if query.has_column?(:description) && issue.description? |
| 325 | 325 |
pdf.set_x(10) |
| 326 | 326 |
pdf.set_auto_page_break(true, bottom_margin) |
| 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 |
| 333 | 340 |
pdf.SetFontStyle('B',10)
|
| 334 | 341 |
pdf.RDMCell(0, row_height, '...') |
| public/stylesheets/application.css | ||
|---|---|---|
| 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 | ||
|---|---|---|
| 561 | 561 |
str_big5 = "\xa4@\xa4\xeb".force_encoding('Big5')
|
| 562 | 562 |
issue = Issue.generate!(:subject => str_utf8) |
| 563 | 563 | |
| 564 |
get :index, :project_id => 1,
|
|
| 565 |
:f => ['subject'],
|
|
| 564 |
get :index, :project_id => 1, |
|
| 565 |
:f => ['subject'], |
|
| 566 | 566 |
:op => '=', :values => [str_utf8], |
| 567 | 567 |
:format => 'csv' |
| 568 | 568 |
assert_equal 'text/csv; header=present', @response.content_type |
| ... | ... | |
| 580 | 580 |
str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85".force_encoding('UTF-8')
|
| 581 | 581 |
issue = Issue.generate!(:subject => str_utf8) |
| 582 | 582 | |
| 583 |
get :index, :project_id => 1,
|
|
| 584 |
:f => ['subject'],
|
|
| 583 |
get :index, :project_id => 1, |
|
| 584 |
:f => ['subject'], |
|
| 585 | 585 |
:op => '=', :values => [str_utf8], |
| 586 | 586 |
:c => ['status', 'subject'], |
| 587 | 587 |
:format => 'csv', |
| ... | ... | |
| 603 | 603 |
str1 = "test_index_csv_tw" |
| 604 | 604 |
issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5') |
| 605 | 605 | |
| 606 |
get :index, :project_id => 1,
|
|
| 607 |
:f => ['subject'],
|
|
| 606 |
get :index, :project_id => 1, |
|
| 607 |
:f => ['subject'], |
|
| 608 | 608 |
:op => '=', :values => [str1], |
| 609 | 609 |
:c => ['estimated_hours', 'subject'], |
| 610 | 610 |
:format => 'csv', |
| ... | ... | |
| 620 | 620 |
str1 = "test_index_csv_fr" |
| 621 | 621 |
issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5') |
| 622 | 622 | |
| 623 |
get :index, :project_id => 1,
|
|
| 624 |
:f => ['subject'],
|
|
| 623 |
get :index, :project_id => 1, |
|
| 624 |
:f => ['subject'], |
|
| 625 | 625 |
:op => '=', :values => [str1], |
| 626 | 626 |
:c => ['estimated_hours', 'subject'], |
| 627 | 627 |
:format => 'csv', |
| ... | ... | |
| 696 | 696 |
assert_response :success |
| 697 | 697 |
end |
| 698 | 698 |
end |
| 699 |
|
|
| 699 | ||
| 700 | 700 |
def test_index_sort_by_assigned_to |
| 701 | 701 |
get :index, :sort => 'assigned_to' |
| 702 | 702 |
assert_response :success |
| 703 |
|
|
| 703 | ||
| 704 | 704 |
assignees = issues_in_list.map(&:assigned_to).compact |
| 705 | 705 |
assert_equal assignees.sort, assignees |
| 706 | 706 |
assert_select 'table.issues.sort-by-assigned-to.sort-asc' |
| 707 | 707 |
end |
| 708 |
|
|
| 708 | ||
| 709 | 709 |
def test_index_sort_by_assigned_to_desc |
| 710 | 710 |
get :index, :sort => 'assigned_to:desc' |
| 711 | 711 |
assert_response :success |
| 712 |
|
|
| 712 | ||
| 713 | 713 |
assignees = issues_in_list.map(&:assigned_to).compact |
| 714 | 714 |
assert_equal assignees.sort.reverse, assignees |
| 715 | 715 |
assert_select 'table.issues.sort-by-assigned-to.sort-desc' |
| 716 | 716 |
end |
| 717 |
|
|
| 717 | ||
| 718 | 718 |
def test_index_group_by_assigned_to |
| 719 | 719 |
get :index, :group_by => 'assigned_to', :sort => 'priority' |
| 720 | 720 |
assert_response :success |
| 721 | 721 |
end |
| 722 |
|
|
| 722 | ||
| 723 | 723 |
def test_index_sort_by_author |
| 724 | 724 |
get :index, :sort => 'author', :c => ['author'] |
| 725 | 725 |
assert_response :success |
| 726 |
|
|
| 726 | ||
| 727 | 727 |
authors = issues_in_list.map(&:author) |
| 728 | 728 |
assert_equal authors.sort, authors |
| 729 | 729 |
end |
| ... | ... | |
| 731 | 731 |
def test_index_sort_by_author_desc |
| 732 | 732 |
get :index, :sort => 'author:desc' |
| 733 | 733 |
assert_response :success |
| 734 |
|
|
| 734 | ||
| 735 | 735 |
authors = issues_in_list.map(&:author) |
| 736 | 736 |
assert_equal authors.sort.reverse, authors |
| 737 | 737 |
end |
| 738 |
|
|
| 738 | ||
| 739 | 739 |
def test_index_group_by_author |
| 740 | 740 |
get :index, :group_by => 'author', :sort => 'priority' |
| 741 | 741 |
assert_response :success |
| 742 | 742 |
end |
| 743 |
|
|
| 743 | ||
| 744 | 744 |
def test_index_sort_by_spent_hours |
| 745 | 745 |
get :index, :sort => 'spent_hours:desc' |
| 746 | 746 |
assert_response :success |
| 747 | 747 |
hours = issues_in_list.map(&:spent_hours) |
| 748 | 748 |
assert_equal hours.sort.reverse, hours |
| 749 | 749 |
end |
| 750 |
|
|
| 750 | ||
| 751 | 751 |
def test_index_sort_by_total_spent_hours |
| 752 | 752 |
get :index, :sort => 'total_spent_hours:desc' |
| 753 | 753 |
assert_response :success |
| 754 | 754 |
hours = issues_in_list.map(&:total_spent_hours) |
| 755 | 755 |
assert_equal hours.sort.reverse, hours |
| 756 | 756 |
end |
| 757 |
|
|
| 757 | ||
| 758 | 758 |
def test_index_sort_by_total_estimated_hours |
| 759 | 759 |
get :index, :sort => 'total_estimated_hours:desc' |
| 760 | 760 |
assert_response :success |
| ... | ... | |
| 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! |
| ... | ... | |
| 1093 | 1130 |
def test_index_should_not_include_new_issue_tab_for_project_without_trackers |
| 1094 | 1131 |
with_settings :new_item_menu_tab => '1' do |
| 1095 | 1132 |
Project.find(1).trackers.clear |
| 1096 |
|
|
| 1133 | ||
| 1097 | 1134 |
@request.session[:user_id] = 2 |
| 1098 | 1135 |
get :index, :project_id => 1 |
| 1099 | 1136 |
assert_select '#main-menu a.new-issue', 0 |
| ... | ... | |
| 1105 | 1142 |
role = Role.find(1) |
| 1106 | 1143 |
role.remove_permission! :add_issues |
| 1107 | 1144 |
role.add_permission! :copy_issues |
| 1108 |
|
|
| 1145 | ||
| 1109 | 1146 |
@request.session[:user_id] = 2 |
| 1110 | 1147 |
get :index, :project_id => 1 |
| 1111 | 1148 |
assert_select '#main-menu a.new-issue', 0 |
| ... | ... | |
| 1381 | 1418 | |
| 1382 | 1419 |
def test_show_should_display_prev_next_links_with_query_and_sort_on_association |
| 1383 | 1420 |
@request.session[:issue_query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
|
| 1384 |
|
|
| 1421 | ||
| 1385 | 1422 |
%w(project tracker status priority author assigned_to category fixed_version).each do |assoc_sort| |
| 1386 | 1423 |
@request.session['issues_index_sort'] = assoc_sort |
| 1387 | 1424 | |
| ... | ... | |
| 1614 | 1651 |
end |
| 1615 | 1652 | |
| 1616 | 1653 |
def test_show_export_to_pdf |
| 1617 |
issue = Issue.find(3)
|
|
| 1654 |
issue = Issue.find(3) |
|
| 1618 | 1655 |
assert issue.relations.select{|r| r.other_issue(issue).visible?}.present?
|
| 1619 | 1656 |
get :show, :id => 3, :format => 'pdf' |
| 1620 | 1657 |
assert_response :success |
| ... | ... | |
| 2062 | 2099 |
get :new, :project_id => 'invalid' |
| 2063 | 2100 |
assert_response 404 |
| 2064 | 2101 |
end |
| 2065 |
|
|
| 2102 | ||
| 2066 | 2103 |
def test_new_with_parent_id_should_only_propose_valid_trackers |
| 2067 | 2104 |
@request.session[:user_id] = 2 |
| 2068 | 2105 |
t = Tracker.find(3) |
| ... | ... | |
| 2611 | 2648 |
:custom_field_values => {'2' => 'Value for field 2'}}
|
| 2612 | 2649 |
end |
| 2613 | 2650 |
assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id |
| 2614 |
|
|
| 2651 | ||
| 2615 | 2652 |
assert_equal 1, ActionMailer::Base.deliveries.size |
| 2616 | 2653 |
end |
| 2617 | 2654 |
end |
| ... | ... | |
| 2885 | 2922 |
assert_select 'option[value="1"][selected=selected]', :text => 'eCookbook' |
| 2886 | 2923 |
assert_select 'option[value="2"]:not([selected])', :text => 'OnlineStore' |
| 2887 | 2924 |
end |
| 2888 |
assert_select 'input[name=?][value=?]', 'issue[subject]', orig.subject
|
|
| 2925 |
assert_select 'input[name=?][value=?]', 'issue[subject]', orig.subject |
|
| 2889 | 2926 |
assert_select 'input[name=copy_from][value="1"]' |
| 2890 | 2927 |
end |
| 2891 | 2928 |
end |
| ... | ... | |
| 3180 | 3217 |
def test_get_edit_should_display_the_time_entry_form_with_log_time_permission |
| 3181 | 3218 |
@request.session[:user_id] = 2 |
| 3182 | 3219 |
Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
|
| 3183 |
|
|
| 3220 | ||
| 3184 | 3221 |
get :edit, :id => 1 |
| 3185 | 3222 |
assert_select 'input[name=?]', 'time_entry[hours]' |
| 3186 | 3223 |
end |
| ... | ... | |
| 3188 | 3225 |
def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission |
| 3189 | 3226 |
@request.session[:user_id] = 2 |
| 3190 | 3227 |
Role.find_by_name('Manager').remove_permission! :log_time
|
| 3191 |
|
|
| 3228 | ||
| 3192 | 3229 |
get :edit, :id => 1 |
| 3193 | 3230 |
assert_select 'input[name=?]', 'time_entry[hours]', 0 |
| 3194 | 3231 |
end |
| ... | ... | |
| 3833 | 3870 |
assert_response :redirect |
| 3834 | 3871 |
assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id |
| 3835 | 3872 |
end |
| 3836 |
|
|
| 3873 | ||
| 3837 | 3874 |
def test_put_update_should_redirect_with_previous_and_next_issue_ids_params |
| 3838 | 3875 |
@request.session[:user_id] = 2 |
| 3839 | 3876 | |
| ... | ... | |
| 3887 | 3924 | |
| 3888 | 3925 |
assert_select 'select[name=?]', 'issue[project_id]' |
| 3889 | 3926 |
assert_select 'input[name=?]', 'issue[parent_issue_id]' |
| 3890 |
|
|
| 3927 | ||
| 3891 | 3928 |
# Project specific custom field, date type |
| 3892 | 3929 |
field = CustomField.find(9) |
| 3893 | 3930 |
assert !field.is_for_all? |
| 3894 | 3931 |
assert_equal 'date', field.field_format |
| 3895 | 3932 |
assert_select 'input[name=?]', 'issue[custom_field_values][9]' |
| 3896 |
|
|
| 3933 | ||
| 3897 | 3934 |
# System wide custom field |
| 3898 | 3935 |
assert CustomField.find(1).is_for_all? |
| 3899 | 3936 |
assert_select 'select[name=?]', 'issue[custom_field_values][1]' |
| 3900 |
|
|
| 3937 | ||
| 3901 | 3938 |
# Be sure we don't display inactive IssuePriorities |
| 3902 | 3939 |
assert ! IssuePriority.find(15).active? |
| 3903 | 3940 |
assert_select 'select[name=?]', 'issue[priority_id]' do |
| ... | ... | |
| 4084 | 4121 |
:issue => {:priority_id => '',
|
| 4085 | 4122 |
:assigned_to_id => group.id, |
| 4086 | 4123 |
:custom_field_values => {'2' => ''}}
|
| 4087 |
|
|
| 4124 | ||
| 4088 | 4125 |
assert_response 302 |
| 4089 | 4126 |
assert_equal [group, group], Issue.where(:id => [1, 2]).collect {|i| i.assigned_to}
|
| 4090 | 4127 |
end |
| ... | ... | |
| 4390 | 4427 |
assert_select 'option[value="2"]' |
| 4391 | 4428 |
end |
| 4392 | 4429 |
end |
| 4393 |
|
|
| 4430 | ||
| 4394 | 4431 |
def test_bulk_copy_to_another_project |
| 4395 | 4432 |
@request.session[:user_id] = 2 |
| 4396 | 4433 |
assert_difference 'Issue.count', 2 do |
| ... | ... | |
| 4443 | 4480 |
:assigned_to_id => 2) |
| 4444 | 4481 |
] |
| 4445 | 4482 |
assert_difference 'Issue.count', issues.size do |
| 4446 |
post :bulk_update, :ids => issues.map(&:id), :copy => '1',
|
|
| 4483 |
post :bulk_update, :ids => issues.map(&:id), :copy => '1', |
|
| 4447 | 4484 |
:issue => {
|
| 4448 | 4485 |
:project_id => '', :tracker_id => '', :assigned_to_id => '', |
| 4449 | 4486 |
:status_id => '', :start_date => '', :due_date => '' |
| ... | ... | |
| 4475 | 4512 |
@request.session[:user_id] = 2 |
| 4476 | 4513 |
assert_difference 'Issue.count', 2 do |
| 4477 | 4514 |
assert_no_difference 'Project.find(1).issues.count' do |
| 4478 |
post :bulk_update, :ids => [1, 2], :copy => '1',
|
|
| 4515 |
post :bulk_update, :ids => [1, 2], :copy => '1', |
|
| 4479 | 4516 |
:issue => {
|
| 4480 | 4517 |
:project_id => '2', :tracker_id => '', :assigned_to_id => '2', |
| 4481 | 4518 |
:status_id => '1', :start_date => '2009-12-01', :due_date => '2009-12-31' |
| test/unit/query_test.rb | ||
|---|---|---|
| 682 | 682 |
Member.create!(:project_id => 1, :principal => other_group, :role_ids => [1]) |
| 683 | 683 |
User.current = user |
| 684 | 684 | |
| 685 |
with_settings :issue_group_assignment => '1' do
|
|
| 685 |
with_settings :issue_group_assignment => '1' do |
|
| 686 | 686 |
i1 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user) |
| 687 | 687 |
i2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => group) |
| 688 | 688 |
i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => other_group) |
| 689 |
|
|
| 689 | ||
| 690 | 690 |
query = IssueQuery.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
|
| 691 | 691 |
result = query.issues |
| 692 | 692 |
assert_equal Issue.visible.where(:assigned_to_id => ([2] + user.reload.group_ids)).sort_by(&:id), result.sort_by(&:id) |
| 693 |
|
|
| 693 | ||
| 694 | 694 |
assert result.include?(i1) |
| 695 | 695 |
assert result.include?(i2) |
| 696 | 696 |
assert !result.include?(i3) |
| ... | ... | |
| 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}
|