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'] |