Commit e608eb81 authored by Marius Balteanu's avatar Marius Balteanu
Browse files

Adds last activity column to projects list

parent 4a856572
Pipeline #132979787 passed with stage
in 14 minutes and 18 seconds
......@@ -48,31 +48,30 @@ class ProjectsController < ApplicationController
end
retrieve_project_query
scope = project_scope
respond_to do |format|
format.html {
# TODO: see what to do with the board view and pagination
if @query.display_type == 'board'
@entries = scope.to_a
@entries = project_scope.to_a
else
@entry_count = scope.count
@entry_count = @query.result_count
@entry_pages = Paginator.new @entry_count, per_page_option, params['page']
@entries = scope.offset(@entry_pages.offset).limit(@entry_pages.per_page).to_a
@entries = project_scope(:offset => @entry_pages.offset, :limit => @entry_pages.per_page).to_a
end
}
format.api {
@offset, @limit = api_offset_and_limit
@project_count = scope.count
@projects = scope.offset(@offset).limit(@limit).to_a
@project_count = @query.result_count
@projects = project_scope(:offset => @offset, :limit => @limit)
}
format.atom {
projects = scope.reorder(:created_on => :desc).limit(Setting.feeds_limit.to_i).to_a
projects = project_scope(:order => {:created_on => :desc}, :limit => Setting.feeds_limit.to_i).to_a
render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
}
format.csv {
# Export all entries
@entries = scope.to_a
@entries = project_scope.to_a
send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'projects.csv')
}
end
......
......@@ -348,6 +348,7 @@ class Project < ActiveRecord::Base
@due_date = nil
@override_members = nil
@assignable_users = nil
@last_activity_date = nil
base_reload(*args)
end
......@@ -904,6 +905,20 @@ class Project < ActiveRecord::Base
end
end
def last_activity_date
@last_activity_date || fetch_last_activity_date
end
# Preloads last activity date for a collection of projects
def self.load_last_activity_date(projects, user=User.current)
if projects.any?
last_activities = Redmine::Activity::Fetcher.new(User.current).events(nil, nil, :last_by_project => true).to_h
projects.each do |project|
project.instance_variable_set("@last_activity_date", last_activities[project.id])
end
end
end
private
def update_inherited_members
......@@ -1179,4 +1194,9 @@ class Project < ActiveRecord::Base
end
update_attribute :status, STATUS_ARCHIVED
end
def fetch_last_activity_date
latest_activities = Redmine::Activity::Fetcher.new(User.current, :project => self).events(nil, nil, :last_by_project => true)
latest_activities.empty? ? nil : latest_activities.to_h[self.id]
end
end
......@@ -34,7 +34,8 @@ class ProjectQuery < Query
QueryColumn.new(:identifier, :sortable => "#{Project.table_name}.identifier"),
QueryColumn.new(:parent_id, :sortable => "#{Project.table_name}.lft ASC", :default_order => 'desc', :caption => :field_parent),
QueryColumn.new(:is_public, :sortable => "#{Project.table_name}.is_public", :groupable => true),
QueryColumn.new(:created_on, :sortable => "#{Project.table_name}.created_on", :default_order => 'desc')
QueryColumn.new(:created_on, :sortable => "#{Project.table_name}.created_on", :default_order => 'desc'),
QueryColumn.new(:last_activity_date)
]
def initialize(attributes=nil, *args)
......@@ -94,6 +95,13 @@ class ProjectQuery < Query
Project.visible.where(statement)
end
# Returns the project count
def result_count
base_scope.count
rescue ::ActiveRecord::StatementInvalid => e
raise StatementInvalid, e.message
end
def results_scope(options={})
order_option = [group_by_sort_order, (options[:order] || sort_clause)].flatten.reject(&:blank?)
......@@ -110,6 +118,10 @@ class ProjectQuery < Query
scope = scope.preload(:parent)
end
scope
projects = scope.to_a
if has_column?(:last_activity_date)
Project.load_last_activity_date(scope)
end
projects
end
end
......@@ -273,6 +273,7 @@ en:
field_downloads: Downloads
field_author: Author
field_created_on: Created
field_last_activity_date: Last activity
field_updated_on: Updated
field_closed_on: Closed
field_field_format: Format
......
......@@ -228,6 +228,7 @@ pt-BR:
field_downloads: Downloads
field_author: Autor
field_created_on: Criado em
field_last_activity_date: Última atividade
field_updated_on: Alterado em
field_field_format: Formato
field_is_for_all: Para todos os projetos
......
......@@ -57,9 +57,8 @@ module Redmine
scope = (provider_options[:scope] || self)
if from && to
scope = scope.where("#{provider_options[:timestamp]} BETWEEN ? AND ?", from, to)
end
scope = scope.where("#{provider_options[:timestamp]} >= ?", from) if from
scope = scope.where("#{provider_options[:timestamp]} <= ?", to) if to
if options[:author]
return [] if provider_options[:author_key].nil?
......@@ -80,6 +79,10 @@ module Redmine
scope = scope.where(Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym, options))
end
if options[:last_by_project]
scope = scope.group("#{Project.table_name}.id").maximum(provider_options[:timestamp])
end
scope.to_a
end
end
......
......@@ -87,6 +87,7 @@ module Redmine
def events(from = nil, to = nil, options={})
e = []
@options[:limit] = options[:limit]
@options[:last_by_project] = options[:last_by_project] if options[:last_by_project]
@scope.each do |event_type|
constantized_providers(event_type).each do |provider|
......@@ -94,10 +95,14 @@ module Redmine
end
end
e.sort! {|a,b| b.event_datetime <=> a.event_datetime}
if options[:last_by_project]
e.sort!
else
e.sort! {|a,b| b.event_datetime <=> a.event_datetime}
if options[:limit]
e = e.slice(0, options[:limit])
if options[:limit]
e = e.slice(0, options[:limit])
end
end
e
end
......
......@@ -248,6 +248,20 @@ class ProjectsControllerTest < Redmine::ControllerTest
assert_select ".total-for-cf-#{field.id} span.value", :text => '9'
end
def test_index_with_last_activity_date_column
with_settings :project_list_defaults => {'column_names' => %w(name short_description last_activity_date)} do
get :index, :params => {
:display_type => 'list'
}
assert_response :success
end
assert_equal ['Name', 'Description', 'Last activity'], columns_in_list
assert_select 'tr#project-1 td.last_activity_date', :text => format_time(Journal.find(3).created_on)
assert_select 'tr#project-4 td.last_activity_date', :text => ''
end
def test_autocomplete_js
get(
:autocomplete,
......
......@@ -1081,4 +1081,12 @@ class ProjectTest < ActiveSupport::TestCase
assert_equal 'valuea', project.custom_field_value(cf1)
assert_nil project.custom_field_value(cf2)
end
def test_last_activity_date
# Note with id 3 is the last activity on Project 1
assert_equal Journal.find(3).created_on, Project.find(1).last_activity_date
# Project without activity should return nil
assert_equal nil, Project.find(4).last_activity_date
end
end
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment