]> source.dussan.org Git - redmine.git/commitdiff
Adds date range filter and pagination on time entries detail view (closes #434).
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Tue, 26 Feb 2008 18:15:58 +0000 (18:15 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Tue, 26 Feb 2008 18:15:58 +0000 (18:15 +0000)
git-svn-id: http://redmine.rubyforge.org/svn/trunk@1173 e93f8b46-1217-0410-a6f0-8f06a7374b81

34 files changed:
app/controllers/timelog_controller.rb
app/helpers/application_helper.rb
app/helpers/sort_helper.rb
app/helpers/timelog_helper.rb
app/models/time_entry.rb
app/views/timelog/_list.rhtml [new file with mode: 0644]
app/views/timelog/details.rhtml
lang/bg.yml
lang/cs.yml
lang/de.yml
lang/en.yml
lang/es.yml
lang/fi.yml
lang/fr.yml
lang/he.yml
lang/it.yml
lang/ja.yml
lang/ko.yml
lang/lt.yml
lang/nl.yml
lang/pl.yml
lang/pt-br.yml
lang/pt.yml
lang/ro.yml
lang/ru.yml
lang/sr.yml
lang/sv.yml
lang/uk.yml
lang/zh-tw.yml
lang/zh.yml
public/stylesheets/application.css
public/stylesheets/calendar.css
test/fixtures/time_entries.yml
test/functional/timelog_controller_test.rb

index 926fe0c6f75a024db2b410031f6192b857fbaa5e..6ce86fd50618dc3a1a8ffbbbf13d0db532ac0237 100644 (file)
@@ -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
index e39ea09069fc52bf885cb608a6a52a14d21c1b7b..af493b034789ead3a0e81ca34d22c0ce311973db 100644 (file)
@@ -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)
index 155e7e5e3c63dacc40afa839f05db112d79f7fc5..f16ff3c7d3e403668a30f1795cda3bf8e00ffc88 100644 (file)
@@ -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
 
index 22e4eba0b447b49c0c21b2249c75e91310f57ace..2af748f6fd30569d1accc538df66461f4222c4c5 100644 (file)
@@ -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
index 90585707303656321259078913b7723be0d76520..04df5233fa417a4dd78c5b634df26fd911bf5314 100644 (file)
@@ -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 (file)
index 0000000..929d8f7
--- /dev/null
@@ -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>
index 6f119206e1e7f2f207d9705deaac39c4115384a5..0e128f6ae6e25ffb46bab6aef68483669361999e 100644 (file)
@@ -4,48 +4,48 @@
 \r
 <h2><%= l(:label_spent_time) %></h2>\r
 \r
-<h3><%= link_to(@project.name, {:action => 'details', :project_id => @project}) if @project %>\r
-<%= "/ " + link_to_issue(@issue) + h(": #{@issue.subject}") if @issue %></h3>\r
+<% if @issue %>\r
+<h3><%= link_to(@project.name, {:action => 'details', :project_id => @project}) %> / <%= link_to_issue(@issue) %></h3>\r
+<% end %>\r
 \r
-<h3 class="textright"><%= l(:label_total) %>: <%= lwr(:label_f_hour, @total_hours) %></h3>\r
+<% form_remote_tag( :url => {}, :method => :get, :update => 'content' ) do %>\r
+<%= hidden_field_tag 'project_id', params[:project_id] %>\r
+<%= hidden_field_tag 'issue_id', params[:issue_id] if @issue %>\r
 \r
-<% unless @entries.empty? %>\r
-<table class="list">\r
-<thead>\r
-<%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %>\r
-<%= sort_header_tag('user_id', :caption => l(:label_member)) %>\r
-<%= sort_header_tag('activity_id', :caption => l(:label_activity)) %>\r
-<%= sort_header_tag('issue_id', :caption => l(:label_issue)) %>\r
-<th><%= l(:field_comments) %></th>\r
-<%= sort_header_tag('hours', :caption => l(:field_hours)) %>\r
-<th></th>\r
-</thead>\r
-<tbody>\r
-<% @entries.each do |entry| %>\r
-<tr class="<%= cycle("odd", "even") %>">\r
-<td align="center"><%= format_date(entry.spent_on) %></td>\r
-<td align="center"><%= entry.user.name %></td>\r
-<td align="center"><%= entry.activity.name %></td>\r
-<td>\r
-    <% if entry.issue %>\r
-    <div class="tooltip">\r
-    <%= link_to_issue entry.issue %>: <%= h(truncate(entry.issue.subject, 50)) %>\r
-    <span class="tip">\r
-    <%= render_issue_tooltip entry.issue %>\r
-    </span>            \r
-       </div>\r
-       <% end %>\r
-</td>\r
-<td><%=h entry.comments %></td>\r
-<td align="center"><strong><%= entry.hours %></strong></td>\r
-<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>\r
-</tr>\r
+<fieldset><legend><%= l(:label_date_range) %></legend>\r
+<p>\r
+<%= radio_button_tag 'period_type', '1', !@free_period %>\r
+<%= select_tag 'period', options_for_period_select(params[:period]),\r
+                         :onchange => 'this.form.onsubmit();',\r
+                         :onfocus => '$("period_type_1").checked = true;' %>\r
+</p>\r
+<p>\r
+<%= radio_button_tag 'period_type', '2', @free_period %>\r
+<%= l(:label_date_from) %>\r
+<%= text_field_tag 'from', @from, :size => 10, :onfocus => '$("period_type_2").checked = true;' %> <%= calendar_for('from') %>\r
+<%= l(:label_date_to) %>\r
+<%= text_field_tag 'to', @to, :size => 10, :onfocus => '$("period_type_2").checked = true;' %> <%= calendar_for('to') %>\r
+<%= submit_tag l(:button_submit), :name => nil, :onclick => '$("period_type_2").checked = true;' %>\r
+</p>\r
+</fieldset>\r
 <% end %>\r
-</tbdoy>\r
-</table>\r
 \r
+<div class="total-hours">\r
+<p><%= l(:label_total) %>: <%= html_hours(lwr(:label_f_hour, @total_hours)) %></p>\r
+</div>\r
+\r
+<% unless @entries.empty? %>\r
+<%= render :partial => 'list', :locals => { :entries => @entries }%>\r
 <div class="contextual">\r
-<%= l(:label_export_to) %>\r
-<%= link_to 'CSV', params.update(:export => 'csv'), :class => 'icon icon-csv' %>\r
+    <%= l(:label_export_to) %>\r
+    <%= link_to 'CSV', params.merge(:format => 'csv'), :class => 'icon icon-csv' %>\r
 </div>\r
-<% end %>
\ No newline at end of file
+<p class="pagination"><%= pagination_links_full @entry_pages, @entry_count %></p>\r
+<% end %>\r
+\r
+<% content_for :header_tags do %>\r
+    <%= javascript_include_tag 'calendar/calendar' %>\r
+    <%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>\r
+    <%= javascript_include_tag 'calendar/calendar-setup' %>\r
+    <%= stylesheet_link_tag 'calendar' %>\r
+<% end %>\r
index a0f439eab2b8e780dad6fe008b1fb6799fd2c5e5..debb643cc6d5278e80f47661dc8adf3e2eddc2d9 100644 (file)
@@ -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
index d952ffd57f7c5705ee976079a2e64b1b49b569f1..2ff8623723d776ded54371fb6acc5a563a1ccf4d 100644 (file)
@@ -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
index 15b033b049bd85f6efde4efae83a6722fe0a4f72..b12f558d0eab0b433a333334f05e51828185112e 100644 (file)
@@ -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
index 509fe4252313e9ee9154c4e076b11ad1e1ea35ad..dadd0a4e58a7c86a7da65a6ef2e47460981ce457 100644 (file)
@@ -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
index 0b048af9b63a64a9630912b1a10bd189e48b85ca..1fd355cd27cec9cf1f3b1cc406ec5de19ae10d06 100644 (file)
@@ -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
index aa6bb28348ca6d269e87641165dad365734a0167..351c47c1b5a70d602c38d249a01347221c409270 100644 (file)
@@ -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
index 97469d7dfc0b5d84cdc329b4c9386c3a68a099c0..73d2e0af652df9d2b956c8d03881a88699e72a5d 100644 (file)
@@ -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
index 578e30814843666e7d64ecc59336dffaa6f94f75..d0071e26f789fa1fbb7da6c005dbd83b1fc30e43 100644 (file)
@@ -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
index 650390a88e91954608245d67884ed681be390ab7..7c6f179862567520b22885e99acc2d8b28920d6c 100644 (file)
@@ -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
index e926e9255da5b42307e2efcd8752f1ca62640f47..bc5303f8fa3aac4972985cdb09bb850580a0bdfd 100644 (file)
@@ -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
index cef2494a44d6b1f662fe240a0cb469c926acd2c4..bb112c25960f3fe08cc9e22784d608f12481426d 100644 (file)
@@ -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
index e49346d3e1d2cc9f616fd365b9af7363214a837e..eb5a5d6e99b28bbe76eb2e2d0ba7581c0402a48a 100644 (file)
@@ -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
index 5f711eef2aa6f1c7054b25b6442edc00ed0bb668..c9bd74db74e8b01322d680516b24a831d03bb99f 100644 (file)
@@ -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
index 51b9930cb94d927855cab74480f67bf915e9b0f9..927025ece77a4f89917c4d8b32d8a9ca85e9498f 100644 (file)
@@ -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
index 3d47c141776015dc4dcffb2b3a1138e79990f109..003940ced2c0724c3c5f26a9fea4be54fc692194 100644 (file)
@@ -592,3 +592,11 @@ button_configure: Configure
 label_plugins: Plugins\r
 label_ldap_authentication: LDAP authentication\r
 label_downloads_abbr: D/L\r
+label_this_month: this month\r
+label_last_n_days: last %d days\r
+label_all_time: all time\r
+label_this_year: this year\r
+label_date_range: Date range\r
+label_last_week: last week\r
+label_yesterday: yesterday\r
+label_last_month: last month\r
index 578a556fec6d7b39ef7d0a8b6cacfa1ba4f27c44..0649005e8c0ce3df833a6f4de204b285a14a3dba 100644 (file)
@@ -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
index 2139442b5e97a65495631d445edadd1ce590dad0..7e71846b2116a6c6260012f6b1d95bb6956f50fa 100644 (file)
@@ -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
index e4b3272f6a6f5142719fcd90679ee18dcbf84b96..d0c4ddef98d08a04353641a93198bf19a83d2f86 100644 (file)
@@ -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
index 0972f507dd1b424fa4d49623c391659976b728b9..f1ed258827afb09e17a527baf480d2e0e803e967 100644 (file)
@@ -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
index f370da42bcf12fa91861aedf46a2c5f5d1f44455..9bd7e0d4c1ceec2e58bfdd87e9dd500e1851e0ca 100644 (file)
@@ -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
index 82d2856b505290ebefafc9d34c9d1ea9df105bbe..b0c73b85b8c4e8c8f7847c944883b7d195af908b 100644 (file)
@@ -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
index 439647ff88d19f13f2a5e211864280b2855e16a3..ab2947676706af259c2f15a81f9b42cb947f6f5d 100644 (file)
@@ -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
index 70d97c78115c3ad3411185c63808cd401ccfd9a6..ae2faf23cb8595ae55bea96fa050513011fecbd8 100644 (file)
@@ -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
index cffcab26feec987c5757ebb419dc1a221bee8a82..003b21ecaa7e4fd1ccda31ee1eb8563565b89d95 100644 (file)
@@ -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%; }
 
index 842dbf71aff586990c715a9490928587a1daf816..c8d2dd6193a41ec0ec48aa458af811684eefe553 100644 (file)
@@ -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;
index 4e4ff68963a36b8a3a28f886c6017d9a2dd76d0b..ae2b1efeadaf5741132a372142508df41339a222 100644 (file)
@@ -21,7 +21,7 @@ time_entries_002:
   comments: ""\r
   updated_on: 2007-03-23 14:11:04 +01:00\r
   activity_id: 8\r
-  spent_on: 2007-03-23\r
+  spent_on: 2007-03-12\r
   issue_id: 1\r
   id: 2\r
   hours: 150.0\r
index 62f1a2e7f9d22f218a0ab5ec824686dcb6321204..e1236ffac399c65aea6011b25852d3bae6b01091 100644 (file)
@@ -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