Feature #23954 » 0001-Adds-last-activity-column-to-projects-list.patch
| app/controllers/projects_controller.rb | ||
|---|---|---|
| 48 | 48 |
end |
| 49 | 49 | |
| 50 | 50 |
retrieve_project_query |
| 51 |
scope = project_scope |
|
| 52 | 51 | |
| 53 | 52 |
respond_to do |format| |
| 54 | 53 |
format.html {
|
| 55 | 54 |
# TODO: see what to do with the board view and pagination |
| 56 | 55 |
if @query.display_type == 'board' |
| 57 |
@entries = scope.to_a |
|
| 56 |
@entries = project_scope.to_a
|
|
| 58 | 57 |
else |
| 59 |
@entry_count = scope.count
|
|
| 58 |
@entry_count = @query.result_count
|
|
| 60 | 59 |
@entry_pages = Paginator.new @entry_count, per_page_option, params['page'] |
| 61 |
@entries = scope.offset(@entry_pages.offset).limit(@entry_pages.per_page).to_a
|
|
| 60 |
@entries = project_scope(:offset => @entry_pages.offset, :limit => @entry_pages.per_page).to_a
|
|
| 62 | 61 |
end |
| 63 | 62 |
} |
| 64 | 63 |
format.api {
|
| 65 | 64 |
@offset, @limit = api_offset_and_limit |
| 66 |
@project_count = scope.count
|
|
| 67 |
@projects = scope.offset(@offset).limit(@limit).to_a
|
|
| 65 |
@project_count = @query.result_count
|
|
| 66 |
@projects = project_scope(:offset => @offset, :limit => @limit)
|
|
| 68 | 67 |
} |
| 69 | 68 |
format.atom {
|
| 70 |
projects = scope.reorder(:created_on => :desc).limit(Setting.feeds_limit.to_i).to_a
|
|
| 69 |
projects = project_scope(:order => {:created_on => :desc}, :limit => Setting.feeds_limit.to_i).to_a
|
|
| 71 | 70 |
render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
|
| 72 | 71 |
} |
| 73 | 72 |
format.csv {
|
| 74 | 73 |
# Export all entries |
| 75 |
@entries = scope.to_a |
|
| 74 |
@entries = project_scope.to_a
|
|
| 76 | 75 |
send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'projects.csv') |
| 77 | 76 |
} |
| 78 | 77 |
end |
| app/models/project.rb | ||
|---|---|---|
| 348 | 348 |
@due_date = nil |
| 349 | 349 |
@override_members = nil |
| 350 | 350 |
@assignable_users = nil |
| 351 |
@last_activity_date = nil |
|
| 351 | 352 |
base_reload(*args) |
| 352 | 353 |
end |
| 353 | 354 | |
| ... | ... | |
| 904 | 905 |
end |
| 905 | 906 |
end |
| 906 | 907 | |
| 908 |
def last_activity_date |
|
| 909 |
@last_activity_date || fetch_last_activity_date |
|
| 910 |
end |
|
| 911 | ||
| 912 |
# Preloads last activity date for a collection of projects |
|
| 913 |
def self.load_last_activity_date(projects, user=User.current) |
|
| 914 |
if projects.any? |
|
| 915 |
last_activities = Redmine::Activity::Fetcher.new(User.current).events(nil, nil, :last_by_project => true).to_h |
|
| 916 |
projects.each do |project| |
|
| 917 |
project.instance_variable_set("@last_activity_date", last_activities[project.id])
|
|
| 918 |
end |
|
| 919 |
end |
|
| 920 |
end |
|
| 921 | ||
| 907 | 922 |
private |
| 908 | 923 | |
| 909 | 924 |
def update_inherited_members |
| ... | ... | |
| 1179 | 1194 |
end |
| 1180 | 1195 |
update_attribute :status, STATUS_ARCHIVED |
| 1181 | 1196 |
end |
| 1197 | ||
| 1198 |
def fetch_last_activity_date |
|
| 1199 |
latest_activities = Redmine::Activity::Fetcher.new(User.current, :project => self).events(nil, nil, :last_by_project => true) |
|
| 1200 |
latest_activities.empty? ? nil : latest_activities.to_h[self.id] |
|
| 1201 |
end |
|
| 1182 | 1202 |
end |
| app/models/project_query.rb | ||
|---|---|---|
| 34 | 34 |
QueryColumn.new(:identifier, :sortable => "#{Project.table_name}.identifier"),
|
| 35 | 35 |
QueryColumn.new(:parent_id, :sortable => "#{Project.table_name}.lft ASC", :default_order => 'desc', :caption => :field_parent),
|
| 36 | 36 |
QueryColumn.new(:is_public, :sortable => "#{Project.table_name}.is_public", :groupable => true),
|
| 37 |
QueryColumn.new(:created_on, :sortable => "#{Project.table_name}.created_on", :default_order => 'desc')
|
|
| 37 |
QueryColumn.new(:created_on, :sortable => "#{Project.table_name}.created_on", :default_order => 'desc'),
|
|
| 38 |
QueryColumn.new(:last_activity_date) |
|
| 38 | 39 |
] |
| 39 | 40 | |
| 40 | 41 |
def initialize(attributes=nil, *args) |
| ... | ... | |
| 94 | 95 |
Project.visible.where(statement) |
| 95 | 96 |
end |
| 96 | 97 | |
| 98 |
# Returns the project count |
|
| 99 |
def result_count |
|
| 100 |
base_scope.count |
|
| 101 |
rescue ::ActiveRecord::StatementInvalid => e |
|
| 102 |
raise StatementInvalid, e.message |
|
| 103 |
end |
|
| 104 | ||
| 97 | 105 |
def results_scope(options={})
|
| 98 | 106 |
order_option = [group_by_sort_order, (options[:order] || sort_clause)].flatten.reject(&:blank?) |
| 99 | 107 | |
| ... | ... | |
| 110 | 118 |
scope = scope.preload(:parent) |
| 111 | 119 |
end |
| 112 | 120 | |
| 113 |
scope |
|
| 121 |
projects = scope.to_a |
|
| 122 |
if has_column?(:last_activity_date) |
|
| 123 |
Project.load_last_activity_date(scope) |
|
| 124 |
end |
|
| 125 |
projects |
|
| 114 | 126 |
end |
| 115 | 127 |
end |
| config/locales/en.yml | ||
|---|---|---|
| 273 | 273 |
field_downloads: Downloads |
| 274 | 274 |
field_author: Author |
| 275 | 275 |
field_created_on: Created |
| 276 |
field_last_activity_date: Last activity |
|
| 276 | 277 |
field_updated_on: Updated |
| 277 | 278 |
field_closed_on: Closed |
| 278 | 279 |
field_field_format: Format |
| config/locales/pt-BR.yml | ||
|---|---|---|
| 228 | 228 |
field_downloads: Downloads |
| 229 | 229 |
field_author: Autor |
| 230 | 230 |
field_created_on: Criado em |
| 231 |
field_last_activity_date: Última atividade |
|
| 231 | 232 |
field_updated_on: Alterado em |
| 232 | 233 |
field_field_format: Formato |
| 233 | 234 |
field_is_for_all: Para todos os projetos |
| lib/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb | ||
|---|---|---|
| 57 | 57 | |
| 58 | 58 |
scope = (provider_options[:scope] || self) |
| 59 | 59 | |
| 60 |
if from && to |
|
| 61 |
scope = scope.where("#{provider_options[:timestamp]} BETWEEN ? AND ?", from, to)
|
|
| 62 |
end |
|
| 60 |
scope = scope.where("#{provider_options[:timestamp]} >= ?", from) if from
|
|
| 61 |
scope = scope.where("#{provider_options[:timestamp]} <= ?", to) if to
|
|
| 63 | 62 | |
| 64 | 63 |
if options[:author] |
| 65 | 64 |
return [] if provider_options[:author_key].nil? |
| ... | ... | |
| 80 | 79 |
scope = scope.where(Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym, options))
|
| 81 | 80 |
end |
| 82 | 81 | |
| 82 |
if options[:last_by_project] |
|
| 83 |
scope = scope.group("#{Project.table_name}.id").maximum(provider_options[:timestamp])
|
|
| 84 |
end |
|
| 85 | ||
| 83 | 86 |
scope.to_a |
| 84 | 87 |
end |
| 85 | 88 |
end |
| lib/redmine/activity/fetcher.rb | ||
|---|---|---|
| 87 | 87 |
def events(from = nil, to = nil, options={})
|
| 88 | 88 |
e = [] |
| 89 | 89 |
@options[:limit] = options[:limit] |
| 90 |
@options[:last_by_project] = options[:last_by_project] if options[:last_by_project] |
|
| 90 | 91 | |
| 91 | 92 |
@scope.each do |event_type| |
| 92 | 93 |
constantized_providers(event_type).each do |provider| |
| ... | ... | |
| 94 | 95 |
end |
| 95 | 96 |
end |
| 96 | 97 | |
| 97 |
e.sort! {|a,b| b.event_datetime <=> a.event_datetime}
|
|
| 98 |
if options[:last_by_project] |
|
| 99 |
e.sort! |
|
| 100 |
else |
|
| 101 |
e.sort! {|a,b| b.event_datetime <=> a.event_datetime}
|
|
| 98 | 102 | |
| 99 |
if options[:limit] |
|
| 100 |
e = e.slice(0, options[:limit]) |
|
| 103 |
if options[:limit] |
|
| 104 |
e = e.slice(0, options[:limit]) |
|
| 105 |
end |
|
| 101 | 106 |
end |
| 102 | 107 |
e |
| 103 | 108 |
end |
| test/functional/projects_controller_test.rb | ||
|---|---|---|
| 248 | 248 |
assert_select ".total-for-cf-#{field.id} span.value", :text => '9'
|
| 249 | 249 |
end |
| 250 | 250 | |
| 251 |
def test_index_with_last_activity_date_column |
|
| 252 |
with_settings :project_list_defaults => {'column_names' => %w(name short_description last_activity_date)} do
|
|
| 253 |
get :index, :params => {
|
|
| 254 |
:display_type => 'list' |
|
| 255 |
} |
|
| 256 |
assert_response :success |
|
| 257 |
end |
|
| 258 | ||
| 259 |
assert_equal ['Name', 'Description', 'Last activity'], columns_in_list |
|
| 260 | ||
| 261 |
assert_select 'tr#project-1 td.last_activity_date', :text => format_time(Journal.find(3).created_on) |
|
| 262 |
assert_select 'tr#project-4 td.last_activity_date', :text => '' |
|
| 263 |
end |
|
| 264 | ||
| 251 | 265 |
def test_autocomplete_js |
| 252 | 266 |
get( |
| 253 | 267 |
:autocomplete, |
| test/unit/project_test.rb | ||
|---|---|---|
| 1081 | 1081 |
assert_equal 'valuea', project.custom_field_value(cf1) |
| 1082 | 1082 |
assert_nil project.custom_field_value(cf2) |
| 1083 | 1083 |
end |
| 1084 | ||
| 1085 |
def test_last_activity_date |
|
| 1086 |
# Note with id 3 is the last activity on Project 1 |
|
| 1087 |
assert_equal Journal.find(3).created_on, Project.find(1).last_activity_date |
|
| 1088 | ||
| 1089 |
# Project without activity should return nil |
|
| 1090 |
assert_equal nil, Project.find(4).last_activity_date |
|
| 1091 |
end |
|
| 1084 | 1092 |
end |
- « Previous
- 1
- …
- 7
- 8
- 9
- Next »