From 328df74dd1779963b80317b72e56aa2a4ea5e2f2 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Tue, 26 Feb 2008 18:15:58 +0000 Subject: [PATCH] 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 --- app/controllers/timelog_controller.rb | 116 ++++++++++++++------- app/helpers/application_helper.rb | 4 + app/helpers/sort_helper.rb | 10 +- app/helpers/timelog_helper.rb | 47 +++++++++ app/models/time_entry.rb | 7 +- app/views/timelog/_list.rhtml | 32 ++++++ app/views/timelog/details.rhtml | 78 +++++++------- lang/bg.yml | 8 ++ lang/cs.yml | 8 ++ lang/de.yml | 8 ++ lang/en.yml | 8 ++ lang/es.yml | 8 ++ lang/fi.yml | 8 ++ lang/fr.yml | 8 ++ lang/he.yml | 8 ++ lang/it.yml | 8 ++ lang/ja.yml | 8 ++ lang/ko.yml | 8 ++ lang/lt.yml | 8 ++ lang/nl.yml | 8 ++ lang/pl.yml | 8 ++ lang/pt-br.yml | 8 ++ lang/pt.yml | 8 ++ lang/ro.yml | 8 ++ lang/ru.yml | 8 ++ lang/sr.yml | 8 ++ lang/sv.yml | 8 ++ lang/uk.yml | 8 ++ lang/zh-tw.yml | 8 ++ lang/zh.yml | 8 ++ public/stylesheets/application.css | 7 ++ public/stylesheets/calendar.css | 2 +- test/fixtures/time_entries.yml | 2 +- test/functional/timelog_controller_test.rb | 50 ++++++++- 34 files changed, 452 insertions(+), 87 deletions(-) create mode 100644 app/views/timelog/_list.rhtml 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+)}, '\1.\2') + 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 @@ + + +<%= 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') %> + +<%= sort_header_tag('hours', :caption => l(:field_hours)) %> + + + +<% entries.each do |entry| -%> +"> + + + + + + + + +<% end -%> + +
<%= l(:field_comments) %>
<%= format_date(entry.spent_on) %><%= entry.user.name %><%= entry.activity.name %> + <% if entry.issue -%> +
<%= link_to_issue entry.issue %>: <%= h(truncate(entry.issue.subject, 50)) -%> + <%= render_issue_tooltip entry.issue %> +
+ <% end -%> +
<%=h entry.comments %><%= entry.hours %><%= link_to_if_authorized(l(:button_edit), + {:controller => 'timelog', :action => 'edit', :id => entry}, + :class => 'icon icon-edit') if entry.editable_by?(User.current) %>
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 @@

<%= l(:label_spent_time) %>

-

<%= link_to(@project.name, {:action => 'details', :project_id => @project}) if @project %> -<%= "/ " + link_to_issue(@issue) + h(": #{@issue.subject}") if @issue %>

+<% if @issue %> +

<%= link_to(@project.name, {:action => 'details', :project_id => @project}) %> / <%= link_to_issue(@issue) %>

+<% end %> -

<%= l(:label_total) %>: <%= lwr(:label_f_hour, @total_hours) %>

+<% 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? %> - - -<%= 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)) %> - -<%= sort_header_tag('hours', :caption => l(:field_hours)) %> - - - -<% @entries.each do |entry| %> -"> - - - - - - - - +
<%= l(:label_date_range) %> +

+<%= 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;' %> +

+

+<%= 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;' %> +

+
<% end %> - -
<%= l(:field_comments) %>
<%= format_date(entry.spent_on) %><%= entry.user.name %><%= entry.activity.name %> - <% if entry.issue %> -
- <%= link_to_issue entry.issue %>: <%= h(truncate(entry.issue.subject, 50)) %> - - <%= render_issue_tooltip entry.issue %> - -
- <% end %> -
<%=h entry.comments %><%= entry.hours %><%= link_to_if_authorized(l(:button_edit), {:controller => 'timelog', :action => 'edit', :id => entry}, :class => "icon icon-edit") if entry.user_id == @owner_id %>
+
+

<%= l(:label_total) %>: <%= html_hours(lwr(:label_f_hour, @total_hours)) %>

+
+ +<% unless @entries.empty? %> +<%= render :partial => 'list', :locals => { :entries => @entries }%>
-<%= 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' %>
-<% end %> \ No newline at end of file +

<%= pagination_links_full @entry_pages, @entry_count %>

+<% 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 -- 2.39.5