Feature #6375 » 6375_add_last_updated_by_column_r16248_v3.patch
| app/models/issue.rb | ||
|---|---|---|
| 245 | 245 |
@spent_hours = nil |
| 246 | 246 |
@total_spent_hours = nil |
| 247 | 247 |
@total_estimated_hours = nil |
| 248 |
@last_updated_by = nil |
|
| 248 | 249 |
base_reload(*args) |
| 249 | 250 |
end |
| 250 | 251 | |
| ... | ... | |
| 1069 | 1070 |
@relations ||= IssueRelation::Relations.new(self, (relations_from + relations_to).sort) |
| 1070 | 1071 |
end |
| 1071 | 1072 | |
| 1073 |
def last_updated_by |
|
| 1074 |
if @last_updated_by |
|
| 1075 |
@last_updated_by |
|
| 1076 |
else |
|
| 1077 |
journal = self.journals.preload(:user).visible.last |
|
| 1078 |
journal.user if journal |
|
| 1079 |
end |
|
| 1080 |
end |
|
| 1081 | ||
| 1072 | 1082 |
# Preloads relations for a collection of issues |
| 1073 | 1083 |
def self.load_relations(issues) |
| 1074 | 1084 |
if issues.any? |
| ... | ... | |
| 1132 | 1142 |
where(:ancestors => {:id => issues.map(&:id)})
|
| 1133 | 1143 |
end |
| 1134 | 1144 | |
| 1145 |
# Preloads users who updated last a collection of issues |
|
| 1146 |
def self.load_visible_last_updated_by(issues) |
|
| 1147 |
if issues.any? |
|
| 1148 |
issue_ids = issues.map(&:id) |
|
| 1149 |
journals = Journal.joins(issue: :project).preload(:user). |
|
| 1150 |
where(:journalized_type => 'Issue', :journalized_id => issue_ids). |
|
| 1151 |
where(Journal.visible_notes_condition(User.current, :skip_pre_condition => true)).to_a |
|
| 1152 | ||
| 1153 |
issues.each do |issue| |
|
| 1154 |
journal = journals.select{|journal| journal.journalized_id == issue.id}
|
|
| 1155 |
issue.instance_variable_set "@last_updated_by", (journal.empty? ? '' : journal.last.user) |
|
| 1156 |
end |
|
| 1157 |
end |
|
| 1158 |
end |
|
| 1159 | ||
| 1135 | 1160 |
# Finds an issue relation given its id. |
| 1136 | 1161 |
def find_relation(relation_id) |
| 1137 | 1162 |
IssueRelation.where("issue_to_id = ? OR issue_from_id = ?", id, id).find(relation_id)
|
| app/models/issue_query.rb | ||
|---|---|---|
| 43 | 43 |
QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true),
|
| 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 |
QueryColumn.new(:last_updated_by, :sortable => lambda {User.fields_for_order_statement("last_journal_user")}),
|
|
| 46 | 47 |
QueryColumn.new(:relations, :caption => :label_related_issues), |
| 47 | 48 |
QueryColumn.new(:description, :inline => false) |
| 48 | 49 |
] |
| ... | ... | |
| 294 | 295 |
if has_column?(:total_spent_hours) |
| 295 | 296 |
Issue.load_visible_total_spent_hours(issues) |
| 296 | 297 |
end |
| 298 |
if has_column?(:last_updated_by) |
|
| 299 |
Issue.load_visible_last_updated_by(issues) |
|
| 300 |
end |
|
| 297 | 301 |
if has_column?(:relations) |
| 298 | 302 |
Issue.load_visible_relations(issues) |
| 299 | 303 |
end |
| ... | ... | |
| 556 | 560 |
if order_options.include?('users')
|
| 557 | 561 |
joins << "LEFT OUTER JOIN #{User.table_name} ON #{User.table_name}.id = #{queried_table_name}.assigned_to_id"
|
| 558 | 562 |
end |
| 563 |
if order_options.include?('last_journal_user')
|
|
| 564 |
joins << "LEFT OUTER JOIN #{Journal.table_name} ON #{Journal.table_name}.id = (SELECT MAX(#{Journal.table_name}.id) FROM #{Journal.table_name}" +
|
|
| 565 |
" WHERE #{Journal.table_name}.journalized_type='Issue' AND #{Journal.table_name}.journalized_id=#{Issue.table_name}.id AND #{Journal.visible_notes_condition(User.current, :skip_pre_condition => true)})" +
|
|
| 566 |
" LEFT OUTER JOIN #{User.table_name} last_journal_user ON last_journal_user.id = #{Journal.table_name}.user_id";
|
|
| 567 |
end |
|
| 559 | 568 |
if order_options.include?('versions')
|
| 560 | 569 |
joins << "LEFT OUTER JOIN #{Version.table_name} ON #{Version.table_name}.id = #{queried_table_name}.fixed_version_id"
|
| 561 | 570 |
end |
| public/stylesheets/application.css | ||
|---|---|---|
| 254 | 254 |
tr.project.idnt-9 td.name {padding-left: 12.5em;}
|
| 255 | 255 | |
| 256 | 256 |
tr.issue { text-align: center; white-space: nowrap; }
|
| 257 |
tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, tr.issue td.text, tr.issue td.list, tr.issue td.relations, tr.issue td.parent { white-space: normal; }
|
|
| 257 |
tr.issue td.subject, tr.issue td.category, td.assigned_to, td.last_updated_by, tr.issue td.string, tr.issue td.text, tr.issue td.list, tr.issue td.relations, tr.issue td.parent { white-space: normal; }
|
|
| 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;}
|
| test/unit/query_test.rb | ||
|---|---|---|
| 29 | 29 |
:queries, |
| 30 | 30 |
:projects_trackers, |
| 31 | 31 |
:custom_fields_trackers, |
| 32 |
:workflows |
|
| 32 |
:workflows, :journals
|
|
| 33 | 33 | |
| 34 | 34 |
def setup |
| 35 | 35 |
User.current = nil |
| ... | ... | |
| 759 | 759 |
query = IssueQuery.new(:name => '_') |
| 760 | 760 |
filter_name = "updated_by" |
| 761 | 761 |
assert_include filter_name, query.available_filters.keys |
| 762 |
|
|
| 762 | ||
| 763 | 763 |
query.filters = {filter_name => {:operator => '=', :values => ['me']}}
|
| 764 | 764 |
assert_equal [2], find_issues_with_query(query).map(&:id).sort |
| 765 | 765 |
end |
| ... | ... | |
| 1287 | 1287 |
assert_not_nil issues.first.instance_variable_get("@spent_hours")
|
| 1288 | 1288 |
end |
| 1289 | 1289 | |
| 1290 |
def test_query_should_preload_last_updated_by |
|
| 1291 |
q = IssueQuery.new(:name => '_', :column_names => [:subject, :last_updated_by]) |
|
| 1292 |
assert q.has_column?(:last_updated_by) |
|
| 1293 |
issues = q.issues |
|
| 1294 |
assert_not_nil issues.first.instance_variable_get("@last_updated_by")
|
|
| 1295 |
end |
|
| 1296 | ||
| 1297 |
def test_query_with_last_updated_by_column |
|
| 1298 |
q = IssueQuery.new(:name => '_', :column_names => [:subject, :last_updated_by]) |
|
| 1299 |
q.filters = {"project_id" => {:operator => '=', :values => [1]}}
|
|
| 1300 | ||
| 1301 |
assert_equal ["User", "User", "String", "String", "String", "String", "String"], q.issues.map { |i| i.last_updated_by.class.name}
|
|
| 1302 |
assert_equal ["John Smith", "John Smith", "", "", "", "", ""], q.issues.map { |i| i.last_updated_by.to_s }
|
|
| 1303 |
end |
|
| 1304 | ||
| 1290 | 1305 |
def test_groupable_columns_should_include_custom_fields |
| 1291 | 1306 |
q = IssueQuery.new |
| 1292 | 1307 |
column = q.groupable_columns.detect {|c| c.name == :cf_1}
|
| ... | ... | |
| 1349 | 1364 |
end |
| 1350 | 1365 |
end |
| 1351 | 1366 | |
| 1367 |
def test_sortable_columns_should_sort_last_updated_by_according_to_user_format_setting |
|
| 1368 |
with_settings :user_format => 'lastname_comma_firstname' do |
|
| 1369 |
q = IssueQuery.new |
|
| 1370 |
q.sort_criteria = [['last_updated_by', 'desc']] |
|
| 1371 | ||
| 1372 |
assert q.sortable_columns.has_key?('last_updated_by')
|
|
| 1373 |
assert_equal %w(last_journal_user.lastname last_journal_user.firstname last_journal_user.id), q.sortable_columns['last_updated_by'] |
|
| 1374 |
end |
|
| 1375 |
end |
|
| 1376 | ||
| 1352 | 1377 |
def test_sortable_columns_should_include_custom_field |
| 1353 | 1378 |
q = IssueQuery.new |
| 1354 | 1379 |
assert q.sortable_columns['cf_1'] |