mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-18 00:00:12 +01:00
Statistics for longest running projects now includes completed and hidden projects. fixes #1725
This commit is contained in:
parent
ff9edcc309
commit
2883d1b7f4
6 changed files with 57 additions and 27 deletions
|
|
@ -138,6 +138,14 @@ class Project < ActiveRecord::Base
|
||||||
@age_in_days ||= (Time.current.to_date - created_at.to_date).to_i + 1
|
@age_in_days ||= (Time.current.to_date - created_at.to_date).to_i + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def running_time
|
||||||
|
if completed_at.nil?
|
||||||
|
return age_in_days
|
||||||
|
else
|
||||||
|
return (completed_at.to_date - created_at.to_date).to_i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.import(filename, params, user)
|
def self.import(filename, params, user)
|
||||||
count = 0
|
count = 0
|
||||||
CSV.foreach(filename, headers: true) do |row|
|
CSV.foreach(filename, headers: true) do |row|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ module Stats
|
||||||
end
|
end
|
||||||
|
|
||||||
def runtime
|
def runtime
|
||||||
@runtime ||= user.projects.active.order('created_at ASC').limit(10)
|
@runtime ||= find_top10_longest_running_projects
|
||||||
end
|
end
|
||||||
|
|
||||||
def actions
|
def actions
|
||||||
|
|
@ -18,5 +18,12 @@ module Stats
|
||||||
@actions_last30days ||= Stats::TopProjectsQuery.new(user, 1.month.ago.beginning_of_day).result
|
@actions_last30days ||= Stats::TopProjectsQuery.new(user, 1.month.ago.beginning_of_day).result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_top10_longest_running_projects
|
||||||
|
projects = user.projects.order('created_at ASC')
|
||||||
|
projects.sort{|a,b| b.running_time <=> a.running_time}.take(10)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<% @swf_count ||= 0 -%>
|
<% @swf_count ||= 0 -%>
|
||||||
<div class="open-flash-chart"><%= swf_tag asset_path("open-flash-chart.swf"),
|
<div class="open-flash-chart"><%= swf_tag "open-flash-chart.swf",
|
||||||
:flashvars => { 'width' => chart.width, 'height' => chart.height, 'data' => url_for(:action => chart.action)},
|
:flashvars => { 'width' => chart.width, 'height' => chart.height, 'data' => url_for(:action => chart.action)},
|
||||||
:parameters => { 'allowScriptAccess' => 'sameDomain', 'wmode' => 'transparent'},
|
:parameters => { 'allowScriptAccess' => 'sameDomain', 'wmode' => 'transparent'},
|
||||||
:div_id => "chart_#{@swf_count+=1}",
|
:div_id => "chart_#{@swf_count+=1}",
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,4 @@
|
||||||
|
|
||||||
<%= render :partial => 'projects_list', :locals => {:projects => projects.actions_last30days, :key => 'projects_30days', :n => :count} -%>
|
<%= render :partial => 'projects_list', :locals => {:projects => projects.actions_last30days, :key => 'projects_30days', :n => :count} -%>
|
||||||
|
|
||||||
<%= render :partial => 'projects_list', :locals => {:projects => projects.runtime, :key => 'longrunning', :n => :age_in_days} -%>
|
<%= render :partial => 'projects_list', :locals => {:projects => projects.runtime, :key => 'longrunning', :n => :running_time, :i18n_key => "days_midsentence"} -%>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
<%- i18n_key ||= "actions_midsentence" -%>
|
||||||
<div class="stats_module">
|
<div class="stats_module">
|
||||||
<h3><%= t("stats.top10_#{key}") %></h3>
|
<h3><%= t("stats.top10_#{key}") %></h3>
|
||||||
<% projects.each_with_index do |p, i| -%>
|
<% projects.each_with_index do |p, i| -%>
|
||||||
<%= i + 1 -%> - <%= link_to p.name, project_path(p) %> (<%=p.send(n)%> <%= t('common.actions_midsentence', :count => p.send(n)) %>) <br/>
|
<%= i + 1 -%> - <%= link_to p.name, project_path(p) %> (<%=p.send(n)%> <%= t("common.#{i18n_key}", :count => p.send(n)) %>) <br/>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
<%= render :partial => 'null_list_item', :locals => {:from => projects.size + 1, :to => 10} -%>
|
<%= render :partial => 'null_list_item', :locals => {:from => projects.size + 1, :to => 10} -%>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,40 +2,40 @@ require 'test_helper'
|
||||||
|
|
||||||
class ProjectTest < ActiveSupport::TestCase
|
class ProjectTest < ActiveSupport::TestCase
|
||||||
fixtures :projects, :contexts, :todos, :recurring_todos, :users, :preferences
|
fixtures :projects, :contexts, :todos, :recurring_todos, :users, :preferences
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
@timemachine = projects(:timemachine)
|
@timemachine = projects(:timemachine)
|
||||||
@moremoney = projects(:moremoney)
|
@moremoney = projects(:moremoney)
|
||||||
end
|
end
|
||||||
|
|
||||||
# associations
|
# associations
|
||||||
|
|
||||||
def test_has_default_context
|
def test_has_default_context
|
||||||
assert !@timemachine.default_context.nil?
|
assert !@timemachine.default_context.nil?
|
||||||
assert @timemachine.default_context.name == contexts(:lab).name
|
assert @timemachine.default_context.name == contexts(:lab).name
|
||||||
|
|
||||||
p = Project.new
|
p = Project.new
|
||||||
assert_equal '', p.default_context.name
|
assert_equal '', p.default_context.name
|
||||||
p.default_context = contexts(:agenda)
|
p.default_context = contexts(:agenda)
|
||||||
assert_equal 'agenda', p.default_context.name
|
assert_equal 'agenda', p.default_context.name
|
||||||
end
|
end
|
||||||
|
|
||||||
# validations
|
# validations
|
||||||
|
|
||||||
def test_validate_presence_of_name
|
def test_validate_presence_of_name
|
||||||
@timemachine.name = ""
|
@timemachine.name = ""
|
||||||
assert !@timemachine.save
|
assert !@timemachine.save
|
||||||
assert_equal 1, @timemachine.errors.count
|
assert_equal 1, @timemachine.errors.count
|
||||||
assert_equal "project must have a name", @timemachine.errors[:name][0]
|
assert_equal "project must have a name", @timemachine.errors[:name][0]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_validate_name_is_less_than_256
|
def test_validate_name_is_less_than_256
|
||||||
@timemachine.name = generate_random_string(256)
|
@timemachine.name = generate_random_string(256)
|
||||||
assert !@timemachine.save
|
assert !@timemachine.save
|
||||||
assert_equal 1, @timemachine.errors.count
|
assert_equal 1, @timemachine.errors.count
|
||||||
assert_equal "project name must be less than 256 characters", @timemachine.errors[:name][0]
|
assert_equal "project name must be less than 256 characters", @timemachine.errors[:name][0]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_validate_name_is_unique
|
def test_validate_name_is_unique
|
||||||
newproj = Project.new
|
newproj = Project.new
|
||||||
newproj.name = projects(:timemachine).name
|
newproj.name = projects(:timemachine).name
|
||||||
|
|
@ -44,20 +44,20 @@ class ProjectTest < ActiveSupport::TestCase
|
||||||
assert_equal 1, newproj.errors.count
|
assert_equal 1, newproj.errors.count
|
||||||
assert_equal "already exists", newproj.errors[:name][0]
|
assert_equal "already exists", newproj.errors[:name][0]
|
||||||
end
|
end
|
||||||
|
|
||||||
# state machine
|
# state machine
|
||||||
|
|
||||||
def test_project_initial_state_is_active
|
def test_project_initial_state_is_active
|
||||||
assert_equal :active, @timemachine.aasm.current_state
|
assert_equal :active, @timemachine.aasm.current_state
|
||||||
assert @timemachine.active?
|
assert @timemachine.active?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_hide_project
|
def test_hide_project
|
||||||
@timemachine.hide!
|
@timemachine.hide!
|
||||||
assert_equal :hidden, @timemachine.aasm.current_state
|
assert_equal :hidden, @timemachine.aasm.current_state
|
||||||
assert @timemachine.hidden?
|
assert @timemachine.hidden?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_activate_project
|
def test_activate_project
|
||||||
@timemachine.activate!
|
@timemachine.activate!
|
||||||
assert_equal :active, @timemachine.aasm.current_state
|
assert_equal :active, @timemachine.aasm.current_state
|
||||||
|
|
@ -81,7 +81,7 @@ class ProjectTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
# other tests
|
# other tests
|
||||||
|
|
||||||
def test_review_project
|
def test_review_project
|
||||||
assert_nil @timemachine.last_reviewed
|
assert_nil @timemachine.last_reviewed
|
||||||
assert @timemachine.needs_review?(users(:admin_user))
|
assert @timemachine.needs_review?(users(:admin_user))
|
||||||
|
|
@ -100,7 +100,7 @@ class ProjectTest < ActiveSupport::TestCase
|
||||||
assert_not_nil @timemachine.completed_at, "completed_at not expected to be nil"
|
assert_not_nil @timemachine.completed_at, "completed_at not expected to be nil"
|
||||||
assert_in_delta Time.now, @timemachine.completed_at, 1
|
assert_in_delta Time.now, @timemachine.completed_at, 1
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_delete_project_deletes_todos_within_it
|
def test_delete_project_deletes_todos_within_it
|
||||||
assert_equal 3, @timemachine.todos.count
|
assert_equal 3, @timemachine.todos.count
|
||||||
timemachine_todo_ids = @timemachine.todos.map{ |t| t.id }
|
timemachine_todo_ids = @timemachine.todos.map{ |t| t.id }
|
||||||
|
|
@ -109,7 +109,7 @@ class ProjectTest < ActiveSupport::TestCase
|
||||||
assert !Todo.exists?(t_id)
|
assert !Todo.exists?(t_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_deferred_todos
|
def test_deferred_todos
|
||||||
assert_equal 1, @timemachine.todos.deferred.size
|
assert_equal 1, @timemachine.todos.deferred.size
|
||||||
t = @timemachine.todos.not_completed[0]
|
t = @timemachine.todos.not_completed[0]
|
||||||
|
|
@ -117,7 +117,7 @@ class ProjectTest < ActiveSupport::TestCase
|
||||||
t.save!
|
t.save!
|
||||||
assert_equal 2, Project.find(@timemachine.id).todos.deferred.size
|
assert_equal 2, Project.find(@timemachine.id).todos.deferred.size
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_to_param_returns_id
|
def test_to_param_returns_id
|
||||||
assert_equal '1', @timemachine.to_param
|
assert_equal '1', @timemachine.to_param
|
||||||
end
|
end
|
||||||
|
|
@ -129,29 +129,29 @@ class ProjectTest < ActiveSupport::TestCase
|
||||||
assert_nil p.id
|
assert_nil p.id
|
||||||
assert_equal "", p.name
|
assert_equal "", p.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_name_removes_extra_spaces
|
def test_name_removes_extra_spaces
|
||||||
newproj = Project.new
|
newproj = Project.new
|
||||||
newproj.name = "These Words Have Proximity Issues "
|
newproj.name = "These Words Have Proximity Issues "
|
||||||
assert newproj.save
|
assert newproj.save
|
||||||
assert_equal 0, newproj.errors.count
|
assert_equal 0, newproj.errors.count
|
||||||
assert_equal "These Words Have Proximity Issues", newproj.name
|
assert_equal "These Words Have Proximity Issues", newproj.name
|
||||||
|
|
||||||
# and on update...
|
# and on update...
|
||||||
@timemachine.name = " a time machine needs lots of spaaaaaaace "
|
@timemachine.name = " a time machine needs lots of spaaaaaaace "
|
||||||
assert @timemachine.save
|
assert @timemachine.save
|
||||||
assert_equal "a time machine needs lots of spaaaaaaace", @timemachine.name
|
assert_equal "a time machine needs lots of spaaaaaaace", @timemachine.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_deferred_todo_count
|
def test_deferred_todo_count
|
||||||
assert_equal 1, @timemachine.todos.deferred.count
|
assert_equal 1, @timemachine.todos.deferred.count
|
||||||
assert_equal 0, @moremoney.todos.deferred.count
|
assert_equal 0, @moremoney.todos.deferred.count
|
||||||
|
|
||||||
first_todo = @moremoney.todos[0]
|
first_todo = @moremoney.todos[0]
|
||||||
first_todo.show_from = Time.zone.now + 1.week
|
first_todo.show_from = Time.zone.now + 1.week
|
||||||
first_todo.save!
|
first_todo.save!
|
||||||
assert_equal :deferred, @moremoney.todos[0].aasm.current_state
|
assert_equal :deferred, @moremoney.todos[0].aasm.current_state
|
||||||
|
|
||||||
assert_equal 1, @moremoney.todos.deferred.count
|
assert_equal 1, @moremoney.todos.deferred.count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -233,9 +233,24 @@ class ProjectTest < ActiveSupport::TestCase
|
||||||
p2 = users(:admin_user).projects.create!(:name => "test7")
|
p2 = users(:admin_user).projects.create!(:name => "test7")
|
||||||
p2.created_at = 1.week.ago
|
p2.created_at = 1.week.ago
|
||||||
p2.save!
|
p2.save!
|
||||||
|
|
||||||
p2.reload
|
p2.reload
|
||||||
assert_equal 8, p2.age_in_days
|
assert_equal 8, p2.age_in_days
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_running_time
|
||||||
|
p = users(:admin_user).projects.create!(:name => "test8")
|
||||||
|
p.created_at = 1.week.ago
|
||||||
|
p.save!
|
||||||
|
|
||||||
|
p.reload
|
||||||
|
assert_equal 8, p.running_time
|
||||||
|
|
||||||
|
p.completed_at = 4.days.ago
|
||||||
|
p.save!
|
||||||
|
|
||||||
|
p.reload
|
||||||
|
assert_equal 4, p.running_time
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue