summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2008-02-26 18:15:58 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2008-02-26 18:15:58 +0000
commit328df74dd1779963b80317b72e56aa2a4ea5e2f2 (patch)
treebc34c905768eeae2106de016d9887ba106c14a8a
parent792b7f30e32eec84d6106e947fc3987e4e26a0b0 (diff)
downloadredmine-328df74dd1779963b80317b72e56aa2a4ea5e2f2.tar.gz
redmine-328df74dd1779963b80317b72e56aa2a4ea5e2f2.zip
Adds date range filter and pagination on time entries detail view (closes #434).
git-svn-id: http://redmine.rubyforge.org/svn/trunk@1173 e93f8b46-1217-0410-a6f0-8f06a7374b81
-rw-r--r--app/controllers/timelog_controller.rb116
-rw-r--r--app/helpers/application_helper.rb4
-rw-r--r--app/helpers/sort_helper.rb10
-rw-r--r--app/helpers/timelog_helper.rb47
-rw-r--r--app/models/time_entry.rb7
-rw-r--r--app/views/timelog/_list.rhtml32
-rw-r--r--app/views/timelog/details.rhtml78
-rw-r--r--lang/bg.yml8
-rw-r--r--lang/cs.yml8
-rw-r--r--lang/de.yml8
-rw-r--r--lang/en.yml8
-rw-r--r--lang/es.yml8
-rw-r--r--lang/fi.yml8
-rw-r--r--lang/fr.yml8
-rw-r--r--lang/he.yml8
-rw-r--r--lang/it.yml8
-rw-r--r--lang/ja.yml8
-rw-r--r--lang/ko.yml8
-rw-r--r--lang/lt.yml8
-rw-r--r--lang/nl.yml8
-rw-r--r--lang/pl.yml8
-rw-r--r--lang/pt-br.yml8
-rw-r--r--lang/pt.yml8
-rw-r--r--lang/ro.yml8
-rw-r--r--lang/ru.yml8
-rw-r--r--lang/sr.yml8
-rw-r--r--lang/sv.yml8
-rw-r--r--lang/uk.yml8
-rw-r--r--lang/zh-tw.yml8
-rw-r--r--lang/zh.yml8
-rw-r--r--public/stylesheets/application.css7
-rw-r--r--public/stylesheets/calendar.css2
-rw-r--r--test/fixtures/time_entries.yml2
-rw-r--r--test/functional/timelog_controller_test.rb50
34 files changed, 452 insertions, 87 deletions
diff --git a/app/controllers/timelog_controller.rb b/app/controllers/timelog_controller.rb
index 926fe0c6f..6ce86fd50 100644
--- a/app/controllers/timelog_controller.rb
+++ b/app/controllers/timelog_controller.rb
@@ -23,6 +23,7 @@ class TimelogController < ApplicationController
helper :sort
include SortHelper
helper :issues
+ include TimelogHelper
def report
@available_criterias = { 'version' => {:sql => "#{Issue.table_name}.fixed_version_id",
@@ -104,14 +105,84 @@ class TimelogController < ApplicationController
def details
sort_init 'spent_on', 'desc'
sort_update
-
- @entries = (@issue ? @issue : @project).time_entries.find(:all, :include => [:activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], :order => sort_clause)
- @total_hours = @entries.inject(0) { |sum,entry| sum + entry.hours }
- @owner_id = User.current.id
+ @free_period = false
+ @from, @to = nil, nil
+
+ if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?)
+ case params[:period].to_s
+ when 'today'
+ @from = @to = Date.today
+ when 'yesterday'
+ @from = @to = Date.today - 1
+ when 'current_week'
+ @from = Date.today - (Date.today.cwday - 1)%7
+ @to = @from + 6
+ when 'last_week'
+ @from = Date.today - 7 - (Date.today.cwday - 1)%7
+ @to = @from + 6
+ when '7_days'
+ @from = Date.today - 7
+ @to = Date.today
+ when 'current_month'
+ @from = Date.civil(Date.today.year, Date.today.month, 1)
+ @to = (@from >> 1) - 1
+ when 'last_month'
+ @from = Date.civil(Date.today.year, Date.today.month, 1) << 1
+ @to = (@from >> 1) - 1
+ when '30_days'
+ @from = Date.today - 30
+ @to = Date.today
+ when 'current_year'
+ @from = Date.civil(Date.today.year, 1, 1)
+ @to = Date.civil(Date.today.year, 12, 31)
+ end
+ elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?))
+ begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end
+ begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end
+ @free_period = true
+ else
+ # default
+ end
+
+ @from, @to = @to, @from if @from && @to && @from > @to
- send_csv and return if 'csv' == params[:export]
- render :action => 'details', :layout => false if request.xhr?
+ conditions = nil
+ if @from
+ if @to
+ conditions = ['spent_on BETWEEN ? AND ?', @from, @to]
+ else
+ conditions = ['spent_on >= ?', @from]
+ end
+ elsif @to
+ conditions = ['spent_on <= ?', @to]
+ end
+
+ @owner_id = User.current.id
+
+ respond_to do |format|
+ format.html {
+ # Paginate results
+ @entry_count = (@issue ? @issue : @project).time_entries.count(:conditions => conditions)
+ @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
+ @entries = (@issue ? @issue : @project).time_entries.find(:all,
+ :include => [:activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
+ :conditions => conditions,
+ :order => sort_clause,
+ :limit => @entry_pages.items_per_page,
+ :offset => @entry_pages.current.offset)
+ @total_hours = (@issue ? @issue : @project).time_entries.sum(:hours, :conditions => conditions).to_f
+ render :layout => !request.xhr?
+ }
+ format.csv {
+ # Export all entries
+ @entries = (@issue ? @issue : @project).time_entries.find(:all,
+ :include => [:activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
+ :conditions => conditions,
+ :order => sort_clause)
+ send_data(entries_to_csv(@entries).read, :type => 'text/csv; header=present', :filename => 'timelog.csv')
+ }
+ end
end
def edit
@@ -141,37 +212,4 @@ private
return false
end
end
-
- def send_csv
- ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
- export = StringIO.new
- CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
- # csv header fields
- headers = [l(:field_spent_on),
- l(:field_user),
- l(:field_activity),
- l(:field_issue),
- l(:field_tracker),
- l(:field_subject),
- l(:field_hours),
- l(:field_comments)
- ]
- csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
- # csv lines
- @entries.each do |entry|
- fields = [l_date(entry.spent_on),
- entry.user,
- entry.activity,
- (entry.issue ? entry.issue.id : nil),
- (entry.issue ? entry.issue.tracker : nil),
- (entry.issue ? entry.issue.subject : nil),
- entry.hours,
- entry.comments
- ]
- csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
- end
- end
- export.rewind
- send_data(export.read, :type => 'text/csv; header=present', :filename => 'export.csv')
- end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index e39ea0906..af493b034 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -90,6 +90,10 @@ module ApplicationHelper
include_date ? local.strftime("#{@date_format} #{@time_format}") : local.strftime(@time_format)
end
+ def html_hours(text)
+ text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
+ end
+
def authoring(created, author)
time_tag = content_tag('acronym', distance_of_time_in_words(Time.now, created), :title => format_time(created))
l(:label_added_time_by, author || 'Anonymous', time_tag)
diff --git a/app/helpers/sort_helper.rb b/app/helpers/sort_helper.rb
index 155e7e5e3..f16ff3c7d 100644
--- a/app/helpers/sort_helper.rb
+++ b/app/helpers/sort_helper.rb
@@ -108,13 +108,13 @@ module SortHelper
end
caption = titleize(Inflector::humanize(column)) unless caption
- url = {:sort_key => column, :sort_order => order, :status => params[:status],
- :issue_id => params[:issue_id],
- :project_id => params[:project_id]}
+ sort_options = { :sort_key => column, :sort_order => order }
+ # don't reuse params if filters are present
+ url_options = params.has_key?(:set_filter) ? sort_options : params.merge(sort_options)
link_to_remote(caption,
- {:update => "content", :url => url},
- {:href => url_for(url)}) +
+ {:update => "content", :url => url_options},
+ {:href => url_for(url_options)}) +
(icon ? nbsp(2) + image_tag(icon) : '')
end
diff --git a/app/helpers/timelog_helper.rb b/app/helpers/timelog_helper.rb
index 22e4eba0b..2af748f6f 100644
--- a/app/helpers/timelog_helper.rb
+++ b/app/helpers/timelog_helper.rb
@@ -27,4 +27,51 @@ module TimelogHelper
end
sum
end
+
+ def options_for_period_select(value)
+ options_for_select([[l(:label_all_time), 'all'],
+ [l(:label_today), 'today'],
+ [l(:label_yesterday), 'yesterday'],
+ [l(:label_this_week), 'current_week'],
+ [l(:label_last_week), 'last_week'],
+ [l(:label_last_n_days, 7), '7_days'],
+ [l(:label_this_month), 'current_month'],
+ [l(:label_last_month), 'last_month'],
+ [l(:label_last_n_days, 30), '30_days'],
+ [l(:label_this_year), 'current_year']],
+ value)
+ end
+
+ def entries_to_csv(entries)
+ ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
+ export = StringIO.new
+ CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
+ # csv header fields
+ headers = [l(:field_spent_on),
+ l(:field_user),
+ l(:field_activity),
+ l(:field_issue),
+ l(:field_tracker),
+ l(:field_subject),
+ l(:field_hours),
+ l(:field_comments)
+ ]
+ csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
+ # csv lines
+ entries.each do |entry|
+ fields = [l_date(entry.spent_on),
+ entry.user,
+ entry.activity,
+ (entry.issue ? entry.issue.id : nil),
+ (entry.issue ? entry.issue.tracker : nil),
+ (entry.issue ? entry.issue.subject : nil),
+ entry.hours,
+ entry.comments
+ ]
+ csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
+ end
+ end
+ export.rewind
+ export
+ end
end
diff --git a/app/models/time_entry.rb b/app/models/time_entry.rb
index 905857073..04df5233f 100644
--- a/app/models/time_entry.rb
+++ b/app/models/time_entry.rb
@@ -46,5 +46,10 @@ class TimeEntry < ActiveRecord::Base
self.tyear = spent_on ? spent_on.year : nil
self.tmonth = spent_on ? spent_on.month : nil
self.tweek = spent_on ? Date.civil(spent_on.year, spent_on.month, spent_on.day).cweek : nil
- end
+ end
+
+ # Returns true if the time entry can be edited by usr, otherwise false
+ def editable_by?(usr)
+ usr == self.user
+ end
end
diff --git a/app/views/timelog/_list.rhtml b/app/views/timelog/_list.rhtml
new file mode 100644
index 000000000..929d8f7dd
--- /dev/null
+++ b/app/views/timelog/_list.rhtml
@@ -0,0 +1,32 @@
+<table class="list time-entries">
+<thead>
+<%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %>
+<%= sort_header_tag('user_id', :caption => l(:label_member)) %>
+<%= sort_header_tag('activity_id', :caption => l(:label_activity)) %>
+<%= sort_header_tag('issue_id', :caption => l(:label_issue), :default_order => 'desc') %>
+<th><%= l(:field_comments) %></th>
+<%= sort_header_tag('hours', :caption => l(:field_hours)) %>
+<th></th>
+</thead>
+<tbody>
+<% entries.each do |entry| -%>
+<tr class="time-entry <%= cycle("odd", "even") %>">
+<td class="spent_on"><%= format_date(entry.spent_on) %></td>
+<td class="user"><%= entry.user.name %></td>
+<td class="activity"><%= entry.activity.name %></td>
+<td class="subject">
+ <% if entry.issue -%>
+ <div class="tooltip"><%= link_to_issue entry.issue %>: <%= h(truncate(entry.issue.subject, 50)) -%>
+ <span class="tip"><%= render_issue_tooltip entry.issue %></span>
+ </div>
+ <% end -%>
+</td>
+<td class="comments"><%=h entry.comments %></td>
+<td class="hours"><%= entry.hours %></td>
+<td align="center"><%= link_to_if_authorized(l(:button_edit),
+ {:controller => 'timelog', :action => 'edit', :id => entry},
+ :class => 'icon icon-edit') if entry.editable_by?(User.current) %></td>
+</tr>
+<% end -%>
+</tbdoy>
+</table>
diff --git a/app/views/timelog/details.rhtml b/app/views/timelog/details.rhtml
index 6f119206e..0e128f6ae 100644
--- a/app/views/timelog/details.rhtml
+++ b/app/views/timelog/details.rhtml
@@ -4,48 +4,48 @@
<h2><%= l(:label_spent_time) %></h2>
-<h3><%= link_to(@project.name, {:action => 'details', :project_id => @project}) if @project %>
-<%= "/ " + link_to_issue(@issue) + h(": #{@issue.subject}") if @issue %></h3>
+<% if @issue %>
+<h3><%= link_to(@project.name, {:action => 'details', :project_id => @project}) %> / <%= link_to_issue(@issue) %></h3>
+<% end %>
-<h3 class="textright"><%= l(:label_total) %>: <%= lwr(:label_f_hour, @total_hours) %></h3>
+<% form_remote_tag( :url => {}, :method => :get, :update => 'content' ) do %>
+<%= hidden_field_tag 'project_id', params[:project_id] %>
+<%= hidden_field_tag 'issue_id', params[:issue_id] if @issue %>
-<% unless @entries.empty? %>
-<table class="list">
-<thead>
-<%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %>
-<%= sort_header_tag('user_id', :caption => l(:label_member)) %>
-<%= sort_header_tag('activity_id', :caption => l(:label_activity)) %>
-<%= sort_header_tag('issue_id', :caption => l(:label_issue)) %>
-<th><%= l(:field_comments) %></th>
-<%= sort_header_tag('hours', :caption => l(:field_hours)) %>
-<th></th>
-</thead>
-<tbody>
-<% @entries.each do |entry| %>
-<tr class="<%= cycle("odd", "even") %>">
-<td align="center"><%= format_date(entry.spent_on) %></td>
-<td align="center"><%= entry.user.name %></td>
-<td align="center"><%= entry.activity.name %></td>
-<td>
- <% if entry.issue %>
- <div class="tooltip">
- <%= link_to_issue entry.issue %>: <%= h(truncate(entry.issue.subject, 50)) %>
- <span class="tip">
- <%= render_issue_tooltip entry.issue %>
- </span>
- </div>
- <% end %>
-</td>
-<td><%=h entry.comments %></td>
-<td align="center"><strong><%= entry.hours %></strong></td>
-<td align="center"><%= link_to_if_authorized(l(:button_edit), {:controller => 'timelog', :action => 'edit', :id => entry}, :class => "icon icon-edit") if entry.user_id == @owner_id %></td>
-</tr>
+<fieldset><legend><%= l(:label_date_range) %></legend>
+<p>
+<%= radio_button_tag 'period_type', '1', !@free_period %>
+<%= select_tag 'period', options_for_period_select(params[:period]),
+ :onchange => 'this.form.onsubmit();',
+ :onfocus => '$("period_type_1").checked = true;' %>
+</p>
+<p>
+<%= radio_button_tag 'period_type', '2', @free_period %>
+<%= l(:label_date_from) %>
+<%= text_field_tag 'from', @from, :size => 10, :onfocus => '$("period_type_2").checked = true;' %> <%= calendar_for('from') %>
+<%= l(:label_date_to) %>
+<%= text_field_tag 'to', @to, :size => 10, :onfocus => '$("period_type_2").checked = true;' %> <%= calendar_for('to') %>
+<%= submit_tag l(:button_submit), :name => nil, :onclick => '$("period_type_2").checked = true;' %>
+</p>
+</fieldset>
<% end %>
-</tbdoy>
-</table>
+<div class="total-hours">
+<p><%= l(:label_total) %>: <%= html_hours(lwr(:label_f_hour, @total_hours)) %></p>
+</div>
+
+<% unless @entries.empty? %>
+<%= render :partial => 'list', :locals => { :entries => @entries }%>
<div class="contextual">
-<%= l(:label_export_to) %>
-<%= link_to 'CSV', params.update(:export => 'csv'), :class => 'icon icon-csv' %>
+ <%= l(:label_export_to) %>
+ <%= link_to 'CSV', params.merge(:format => 'csv'), :class => 'icon icon-csv' %>
</div>
-<% end %> \ No newline at end of file
+<p class="pagination"><%= pagination_links_full @entry_pages, @entry_count %></p>
+<% end %>
+
+<% content_for :header_tags do %>
+ <%= javascript_include_tag 'calendar/calendar' %>
+ <%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
+ <%= javascript_include_tag 'calendar/calendar-setup' %>
+ <%= stylesheet_link_tag 'calendar' %>
+<% end %>
diff --git a/lang/bg.yml b/lang/bg.yml
index a0f439eab..debb643cc 100644
--- a/lang/bg.yml
+++ b/lang/bg.yml
@@ -592,3 +592,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/cs.yml b/lang/cs.yml
index d952ffd57..2ff862372 100644
--- a/lang/cs.yml
+++ b/lang/cs.yml
@@ -592,3 +592,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/de.yml b/lang/de.yml
index 15b033b04..b12f558d0 100644
--- a/lang/de.yml
+++ b/lang/de.yml
@@ -592,3 +592,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/en.yml b/lang/en.yml
index 509fe4252..dadd0a4e5 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -362,7 +362,15 @@ label_in_less_than: in less than
label_in_more_than: in more than
label_in: in
label_today: today
+label_all_time: all time
+label_yesterday: yesterday
label_this_week: this week
+label_last_week: last week
+label_last_n_days: last %d days
+label_this_month: this month
+label_last_month: last month
+label_this_year: this year
+label_date_range: Date range
label_less_than_ago: less than days ago
label_more_than_ago: more than days ago
label_ago: days ago
diff --git a/lang/es.yml b/lang/es.yml
index 0b048af9b..1fd355cd2 100644
--- a/lang/es.yml
+++ b/lang/es.yml
@@ -595,3 +595,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/fi.yml b/lang/fi.yml
index aa6bb2834..351c47c1b 100644
--- a/lang/fi.yml
+++ b/lang/fi.yml
@@ -596,3 +596,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/fr.yml b/lang/fr.yml
index 97469d7df..73d2e0af6 100644
--- a/lang/fr.yml
+++ b/lang/fr.yml
@@ -362,7 +362,15 @@ label_in_less_than: dans moins de
label_in_more_than: dans plus de
label_in: dans
label_today: aujourd'hui
+label_all_time: toute la période
+label_yesterday: hier
label_this_week: cette semaine
+label_last_week: la semaine dernière
+label_last_n_days: les %d derniers jours
+label_this_month: ce mois-ci
+label_last_month: le mois dernier
+label_this_year: cette année
+label_date_range: Période
label_less_than_ago: il y a moins de
label_more_than_ago: il y a plus de
label_ago: il y a
diff --git a/lang/he.yml b/lang/he.yml
index 578e30814..d0071e26f 100644
--- a/lang/he.yml
+++ b/lang/he.yml
@@ -592,3 +592,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/it.yml b/lang/it.yml
index 650390a88..7c6f17986 100644
--- a/lang/it.yml
+++ b/lang/it.yml
@@ -592,3 +592,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/ja.yml b/lang/ja.yml
index e926e9255..bc5303f8f 100644
--- a/lang/ja.yml
+++ b/lang/ja.yml
@@ -593,3 +593,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/ko.yml b/lang/ko.yml
index cef2494a4..bb112c259 100644
--- a/lang/ko.yml
+++ b/lang/ko.yml
@@ -592,3 +592,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/lt.yml b/lang/lt.yml
index e49346d3e..eb5a5d6e9 100644
--- a/lang/lt.yml
+++ b/lang/lt.yml
@@ -593,3 +593,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/nl.yml b/lang/nl.yml
index 5f711eef2..c9bd74db7 100644
--- a/lang/nl.yml
+++ b/lang/nl.yml
@@ -593,3 +593,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/pl.yml b/lang/pl.yml
index 51b9930cb..927025ece 100644
--- a/lang/pl.yml
+++ b/lang/pl.yml
@@ -592,3 +592,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/pt-br.yml b/lang/pt-br.yml
index 3d47c1417..003940ced 100644
--- a/lang/pt-br.yml
+++ b/lang/pt-br.yml
@@ -592,3 +592,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/pt.yml b/lang/pt.yml
index 578a556fe..0649005e8 100644
--- a/lang/pt.yml
+++ b/lang/pt.yml
@@ -592,3 +592,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/ro.yml b/lang/ro.yml
index 2139442b5..7e71846b2 100644
--- a/lang/ro.yml
+++ b/lang/ro.yml
@@ -592,3 +592,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/ru.yml b/lang/ru.yml
index e4b3272f6..d0c4ddef9 100644
--- a/lang/ru.yml
+++ b/lang/ru.yml
@@ -596,3 +596,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/sr.yml b/lang/sr.yml
index 0972f507d..f1ed25882 100644
--- a/lang/sr.yml
+++ b/lang/sr.yml
@@ -593,3 +593,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/sv.yml b/lang/sv.yml
index f370da42b..9bd7e0d4c 100644
--- a/lang/sv.yml
+++ b/lang/sv.yml
@@ -593,3 +593,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/uk.yml b/lang/uk.yml
index 82d2856b5..b0c73b85b 100644
--- a/lang/uk.yml
+++ b/lang/uk.yml
@@ -594,3 +594,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/zh-tw.yml b/lang/zh-tw.yml
index 439647ff8..ab2947676 100644
--- a/lang/zh-tw.yml
+++ b/lang/zh-tw.yml
@@ -592,3 +592,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/lang/zh.yml b/lang/zh.yml
index 70d97c781..ae2faf23c 100644
--- a/lang/zh.yml
+++ b/lang/zh.yml
@@ -595,3 +595,11 @@ button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L
+label_this_month: this month
+label_last_n_days: last %d days
+label_all_time: all time
+label_this_year: this year
+label_date_range: Date range
+label_last_week: last week
+label_yesterday: yesterday
+label_last_month: last month
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index cffcab26f..003b21eca 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -110,6 +110,10 @@ tr.user td { white-space: nowrap; }
tr.user.locked, tr.user.registered { color: #aaa; }
tr.user.locked a, tr.user.registered a { color: #aaa; }
+tr.time-entry { text-align: center; white-space: nowrap; }
+tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; }
+tr.time-entry td.hours { text-align: right; font-weight: bold; padding-right: 0.6em; }
+
table.list tbody tr:hover { background-color:#ffffdd; }
table td {padding:2px;}
table p {margin:0;}
@@ -169,6 +173,9 @@ div#roadmap .wiki h1:first-child { display: none; }
div#roadmap .wiki h1 { font-size: 120%; }
div#roadmap .wiki h2 { font-size: 110%; }
+div.total-hours { text-align: left; font-size: 110%; font-weight: bold; }
+div.total-hours span.hours-int { font-size: 120%; }
+
.autoscroll {overflow-x: auto; padding:1px; width:100%; margin-bottom: 1.2em;}
#user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }
diff --git a/public/stylesheets/calendar.css b/public/stylesheets/calendar.css
index 842dbf71a..c8d2dd619 100644
--- a/public/stylesheets/calendar.css
+++ b/public/stylesheets/calendar.css
@@ -6,7 +6,7 @@ img.calendar-trigger {
margin-left: 4px;
}
-div.calendar { position: relative; z-index: 15;}
+div.calendar { position: relative; z-index: 30;}
.calendar, .calendar table {
border: 1px solid #556;
diff --git a/test/fixtures/time_entries.yml b/test/fixtures/time_entries.yml
index 4e4ff6896..ae2b1efea 100644
--- a/test/fixtures/time_entries.yml
+++ b/test/fixtures/time_entries.yml
@@ -21,7 +21,7 @@ time_entries_002:
comments: ""
updated_on: 2007-03-23 14:11:04 +01:00
activity_id: 8
- spent_on: 2007-03-23
+ spent_on: 2007-03-12
issue_id: 1
id: 2
hours: 150.0
diff --git a/test/functional/timelog_controller_test.rb b/test/functional/timelog_controller_test.rb
index 62f1a2e7f..e1236ffac 100644
--- a/test/functional/timelog_controller_test.rb
+++ b/test/functional/timelog_controller_test.rb
@@ -22,7 +22,7 @@ require 'timelog_controller'
class TimelogController; def rescue_action(e) raise e end; end
class TimelogControllerTest < Test::Unit::TestCase
- fixtures :time_entries, :issues
+ fixtures :projects, :issues, :time_entries, :users, :trackers, :enumerations, :issue_statuses
def setup
@controller = TimelogController.new
@@ -49,4 +49,52 @@ class TimelogControllerTest < Test::Unit::TestCase
assert_template 'report'
assert_not_nil assigns(:hours)
end
+
+ def test_details_at_project_level
+ get :details, :project_id => 1
+ assert_response :success
+ assert_template 'details'
+ assert_not_nil assigns(:entries)
+ assert_equal 3, assigns(:entries).size
+ assert_not_nil assigns(:total_hours)
+ assert_equal 155.25, assigns(:total_hours)
+ # display all time by default
+ assert_nil assigns(:from)
+ assert_nil assigns(:to)
+ end
+
+ def test_details_at_project_level_with_date_range
+ get :details, :project_id => 1, :from => '2007-03-20', :to => '2007-04-30'
+ assert_response :success
+ assert_template 'details'
+ assert_not_nil assigns(:entries)
+ assert_equal 2, assigns(:entries).size
+ assert_not_nil assigns(:total_hours)
+ assert_equal 5.25, assigns(:total_hours)
+ assert_equal '2007-03-20'.to_date, assigns(:from)
+ assert_equal '2007-04-30'.to_date, assigns(:to)
+ end
+
+ def test_details_at_project_level_with_period
+ get :details, :project_id => 1, :period => '7_days'
+ assert_response :success
+ assert_template 'details'
+ assert_not_nil assigns(:entries)
+ assert_not_nil assigns(:total_hours)
+ assert_equal Date.today - 7, assigns(:from)
+ assert_equal Date.today, assigns(:to)
+ end
+
+ def test_details_at_issue_level
+ get :details, :issue_id => 1
+ assert_response :success
+ assert_template 'details'
+ assert_not_nil assigns(:entries)
+ assert_equal 2, assigns(:entries).size
+ assert_not_nil assigns(:total_hours)
+ assert_equal 154.25, assigns(:total_hours)
+ # display all time by default
+ assert_nil assigns(:from)
+ assert_nil assigns(:to)
+ end
end