Simple time tracking functionality added. Time can be logged at issue or project level.
There's no aggregation reports for now, it's just possible to see all time entries for a project or an issue. A new "activities" enumeration is added. Permission for a role to log time must be set (new "Time tracking" section in role permissions screen). git-svn-id: http://redmine.rubyforge.org/svn/trunk@368 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
7cf2d889d8
commit
8d54d97007
|
@ -57,6 +57,7 @@ class ReportsController < ApplicationController
|
||||||
issues_by_priority
|
issues_by_priority
|
||||||
issues_by_category
|
issues_by_category
|
||||||
issues_by_author
|
issues_by_author
|
||||||
|
@total_hours = @project.time_entries.sum(:hours)
|
||||||
render :template => "reports/issue_report"
|
render :template => "reports/issue_report"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
class TimelogController < ApplicationController
|
||||||
|
layout 'base'
|
||||||
|
|
||||||
|
before_filter :find_project
|
||||||
|
before_filter :authorize, :only => :edit
|
||||||
|
before_filter :check_project_privacy, :only => :details
|
||||||
|
|
||||||
|
helper :sort
|
||||||
|
include SortHelper
|
||||||
|
|
||||||
|
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 = logged_in_user ? logged_in_user.id : 0
|
||||||
|
|
||||||
|
send_csv and return if 'csv' == params[:export]
|
||||||
|
render :action => 'details', :layout => false if request.xhr?
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
render_404 and return if @time_entry && @time_entry.user != logged_in_user
|
||||||
|
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => logged_in_user, :spent_on => Date.today)
|
||||||
|
@time_entry.attributes = params[:time_entry]
|
||||||
|
if request.post? and @time_entry.save
|
||||||
|
flash[:notice] = l(:notice_successful_update)
|
||||||
|
redirect_to :action => 'details', :project_id => @time_entry.project, :issue_id => @time_entry.issue
|
||||||
|
return
|
||||||
|
end
|
||||||
|
@activities = Enumeration::get_values('ACTI')
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def find_project
|
||||||
|
if params[:id]
|
||||||
|
@time_entry = TimeEntry.find(params[:id])
|
||||||
|
@project = @time_entry.project
|
||||||
|
elsif params[:issue_id]
|
||||||
|
@issue = Issue.find(params[:issue_id])
|
||||||
|
@project = @issue.project
|
||||||
|
elsif params[:project_id]
|
||||||
|
@project = Project.find(params[:project_id])
|
||||||
|
else
|
||||||
|
render_404
|
||||||
|
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_hours),
|
||||||
|
l(:field_comment)
|
||||||
|
]
|
||||||
|
csv << headers.collect {|c| ic.iconv(c) }
|
||||||
|
# csv lines
|
||||||
|
@entries.each do |entry|
|
||||||
|
fields = [l_date(entry.spent_on),
|
||||||
|
entry.user.name,
|
||||||
|
entry.activity.name,
|
||||||
|
(entry.issue ? entry.issue.id : nil),
|
||||||
|
entry.hours,
|
||||||
|
entry.comment
|
||||||
|
]
|
||||||
|
csv << fields.collect {|c| ic.iconv(c.to_s) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
export.rewind
|
||||||
|
send_data(export.read, :type => 'text/csv; header=present', :filename => 'export.csv')
|
||||||
|
end
|
||||||
|
end
|
|
@ -107,10 +107,10 @@ module SortHelper
|
||||||
order = 'desc' # changed for desc order by default
|
order = 'desc' # changed for desc order by default
|
||||||
end
|
end
|
||||||
caption = titleize(Inflector::humanize(column)) unless caption
|
caption = titleize(Inflector::humanize(column)) unless caption
|
||||||
params = {:params => {:sort_key => column, :sort_order => order}}
|
#params = {:params => {:sort_key => column, :sort_order => order}}
|
||||||
link_to_remote(caption,
|
link_to_remote(caption,
|
||||||
{:update => "content", :url => { :sort_key => column, :sort_order => order}},
|
{:update => "content", :url => params.update( :sort_key => column, :sort_order => order)},
|
||||||
{:href => url_for(:params => { :sort_key => column, :sort_order => order})}) +
|
{:href => url_for(:params => params.update(:sort_key => column, :sort_order => order))}) +
|
||||||
(icon ? nbsp(2) + image_tag(icon) : '')
|
(icon ? nbsp(2) + image_tag(icon) : '')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
module TimelogHelper
|
||||||
|
end
|
|
@ -24,7 +24,8 @@ class Enumeration < ActiveRecord::Base
|
||||||
|
|
||||||
OPTIONS = {
|
OPTIONS = {
|
||||||
"IPRI" => :enumeration_issue_priorities,
|
"IPRI" => :enumeration_issue_priorities,
|
||||||
"DCAT" => :enumeration_doc_categories
|
"DCAT" => :enumeration_doc_categories,
|
||||||
|
"ACTI" => :enumeration_activities
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
def self.get_values(option)
|
def self.get_values(option)
|
||||||
|
@ -42,6 +43,8 @@ private
|
||||||
raise "Can't delete enumeration" if Issue.find(:first, :conditions => ["priority_id=?", self.id])
|
raise "Can't delete enumeration" if Issue.find(:first, :conditions => ["priority_id=?", self.id])
|
||||||
when "DCAT"
|
when "DCAT"
|
||||||
raise "Can't delete enumeration" if Document.find(:first, :conditions => ["category_id=?", self.id])
|
raise "Can't delete enumeration" if Document.find(:first, :conditions => ["category_id=?", self.id])
|
||||||
|
when "ACTI"
|
||||||
|
raise "Can't delete enumeration" if TimeEntry.find(:first, :conditions => ["activity_id=?", self.id])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Issue < ActiveRecord::Base
|
||||||
|
|
||||||
has_many :journals, :as => :journalized, :dependent => :destroy
|
has_many :journals, :as => :journalized, :dependent => :destroy
|
||||||
has_many :attachments, :as => :container, :dependent => :destroy
|
has_many :attachments, :as => :container, :dependent => :destroy
|
||||||
|
has_many :time_entries
|
||||||
has_many :custom_values, :dependent => :delete_all, :as => :customized
|
has_many :custom_values, :dependent => :delete_all, :as => :customized
|
||||||
has_many :custom_fields, :through => :custom_values
|
has_many :custom_fields, :through => :custom_values
|
||||||
|
|
||||||
|
@ -92,6 +92,10 @@ class Issue < ActiveRecord::Base
|
||||||
@current_journal
|
@current_journal
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def spent_hours
|
||||||
|
@spent_hours ||= time_entries.sum(:hours) || 0
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
# Creates an history for the issue
|
# Creates an history for the issue
|
||||||
#def build_history
|
#def build_history
|
||||||
|
|
|
@ -30,7 +30,8 @@ class Permission < ActiveRecord::Base
|
||||||
1100 => :label_news_plural,
|
1100 => :label_news_plural,
|
||||||
1200 => :label_document_plural,
|
1200 => :label_document_plural,
|
||||||
1300 => :label_attachment_plural,
|
1300 => :label_attachment_plural,
|
||||||
1400 => :label_repository
|
1400 => :label_repository,
|
||||||
|
1500 => :label_time_tracking
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
@@cached_perms_for_public = nil
|
@@cached_perms_for_public = nil
|
||||||
|
|
|
@ -21,6 +21,7 @@ class Project < ActiveRecord::Base
|
||||||
has_many :users, :through => :members
|
has_many :users, :through => :members
|
||||||
has_many :custom_values, :dependent => :delete_all, :as => :customized
|
has_many :custom_values, :dependent => :delete_all, :as => :customized
|
||||||
has_many :issues, :dependent => :destroy, :order => "#{Issue.table_name}.created_on DESC", :include => [:status, :tracker]
|
has_many :issues, :dependent => :destroy, :order => "#{Issue.table_name}.created_on DESC", :include => [:status, :tracker]
|
||||||
|
has_many :time_entries, :dependent => :delete_all
|
||||||
has_many :queries, :dependent => :delete_all
|
has_many :queries, :dependent => :delete_all
|
||||||
has_many :documents, :dependent => :destroy
|
has_many :documents, :dependent => :destroy
|
||||||
has_many :news, :dependent => :delete_all, :include => :author
|
has_many :news, :dependent => :delete_all, :include => :author
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
class TimeEntry < ActiveRecord::Base
|
||||||
|
# could have used polymorphic association
|
||||||
|
# project association here allows easy loading of time entries at project level with one database trip
|
||||||
|
belongs_to :project
|
||||||
|
belongs_to :issue
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :activity, :class_name => 'Enumeration', :foreign_key => :activity_id
|
||||||
|
|
||||||
|
attr_protected :project_id, :user_id, :tyear, :tmonth, :tweek
|
||||||
|
|
||||||
|
validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
|
||||||
|
validates_numericality_of :hours, :allow_nil => true
|
||||||
|
validates_length_of :comment, :maximum => 255
|
||||||
|
|
||||||
|
def before_validation
|
||||||
|
self.project = issue.project if issue && project.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate
|
||||||
|
errors.add :hours, :activerecord_error_invalid if hours && hours < 0
|
||||||
|
errors.add :project_id, :activerecord_error_invalid if project.nil?
|
||||||
|
errors.add :issue_id, :activerecord_error_invalid if (issue_id && !issue) || (issue && project!=issue.project)
|
||||||
|
end
|
||||||
|
|
||||||
|
# tyear, tmonth, tweek assigned where setting spent_on attributes
|
||||||
|
# these attributes make time aggregations easier
|
||||||
|
def spent_on=(date)
|
||||||
|
super
|
||||||
|
self.tyear = spent_on ? spent_on.year : nil
|
||||||
|
self.tmonth = spent_on ? spent_on.month : nil
|
||||||
|
self.tweek = spent_on ? spent_on.cweek : nil
|
||||||
|
end
|
||||||
|
end
|
|
@ -28,7 +28,8 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b><%=l(:field_fixed_version)%> :</b></td><td><%= @issue.fixed_version ? @issue.fixed_version.name : "-" %></td>
|
<td><b><%=l(:field_fixed_version)%> :</b></td><td><%= @issue.fixed_version ? @issue.fixed_version.name : "-" %></td>
|
||||||
<td></td><td></td>
|
<td><b><%=l(:label_spent_time)%> :</b></td>
|
||||||
|
<td><%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :issue_id => @issue}, :class => 'icon icon-time') : "-" %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<% n = 0
|
<% n = 0
|
||||||
|
@ -51,6 +52,7 @@ end %>
|
||||||
|
|
||||||
<div class="contextual">
|
<div class="contextual">
|
||||||
<%= link_to_if_authorized l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, :class => 'icon icon-edit' %>
|
<%= link_to_if_authorized l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, :class => 'icon icon-edit' %>
|
||||||
|
<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time' %>
|
||||||
<%= link_to_if_authorized l(:button_move), {:controller => 'projects', :action => 'move_issues', :id => @project, "issue_ids[]" => @issue.id }, :class => 'icon icon-move' %>
|
<%= link_to_if_authorized l(:button_move), {:controller => 'projects', :action => 'move_issues', :id => @project, "issue_ids[]" => @issue.id }, :class => 'icon icon-move' %>
|
||||||
<%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
|
<%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<h2><%=l(:label_report_plural)%></h2>
|
<h2><%=l(:label_report_plural)%></h2>
|
||||||
|
|
||||||
|
<div class="splitcontentleft">
|
||||||
<div class="contextual">
|
<div class="contextual">
|
||||||
<%= link_to_if_authorized l(:label_query_new), {:controller => 'projects', :action => 'add_query', :id => @project}, :class => 'icon icon-add' %>
|
<%= link_to_if_authorized l(:label_query_new), {:controller => 'projects', :action => 'add_query', :id => @project}, :class => 'icon icon-add' %>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,6 +12,16 @@
|
||||||
<li><%= link_to query.name, :controller => 'projects', :action => 'list_issues', :id => @project, :query_id => query %></li>
|
<li><%= link_to query.name, :controller => 'projects', :action => 'list_issues', :id => @project, :query_id => query %></li>
|
||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="splitcontentright">
|
||||||
|
<% if @total_hours %>
|
||||||
|
<h3 class="textright"><%= l(:label_spent_time) %>:
|
||||||
|
<%= link_to(lwr(:label_f_hour, @total_hours), {:controller => 'timelog', :action => 'details', :project_id => @project}, :class => 'icon icon-time') %>
|
||||||
|
</h3>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clear"></div>
|
||||||
|
|
||||||
<div class="splitcontentleft">
|
<div class="splitcontentleft">
|
||||||
<h3><%=l(:field_tracker)%> <%= link_to image_tag('zoom_in.png'), :detail => 'tracker' %></h3>
|
<h3><%=l(:field_tracker)%> <%= link_to image_tag('zoom_in.png'), :detail => 'tracker' %></h3>
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
<div class="contextual">
|
||||||
|
<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2><%= l(:label_spent_time) %></h2>
|
||||||
|
|
||||||
|
<h3><%= link_to(@project.name, {:action => 'details', :project_id => @project}) if @project %>
|
||||||
|
<%= "/ " + link_to("#{@issue.tracker.name} ##{@issue.id}", {:action => 'details', :issue_id => @issue }) + ": #{h(@issue.subject)}" if @issue %></h3>
|
||||||
|
|
||||||
|
<h3 class="textright"><%= l(:label_total) %>: <%= lwr(:label_f_hour, @total_hours) %></h3>
|
||||||
|
|
||||||
|
<% unless @entries.empty? %>
|
||||||
|
<table class="list">
|
||||||
|
<thead>
|
||||||
|
<%= sort_header_tag('spent_on', :caption => l(:label_date)) %>
|
||||||
|
<%= 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(:label_comment) %></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 align="center">
|
||||||
|
<% if entry.issue %>
|
||||||
|
<div class="tooltip">
|
||||||
|
<%= link_to "#{entry.issue.tracker.name} ##{entry.issue.id}", {:action => 'details', :issue_id => entry.issue } %>
|
||||||
|
<span class="tip">
|
||||||
|
<%= render :partial => "issues/tooltip", :locals => { :issue => entry.issue }%>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
<td><%=h entry.comment %></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>
|
||||||
|
<% end %>
|
||||||
|
</tbdoy>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="contextual">
|
||||||
|
<%= l(:label_export_to) %>
|
||||||
|
<%= link_to 'CSV', params.update(:export => 'csv'), :class => 'icon icon-csv' %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<h2><%= l(:label_spent_time) %></h2>
|
||||||
|
|
||||||
|
<% labelled_tabular_form_for :time_entry, @time_entry, :url => {:action => 'edit', :project_id => @time_entry.project} do |f| %>
|
||||||
|
<%= error_messages_for 'time_entry' %>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<p><%= f.text_field :issue_id, :size => 6 %> <em><%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %></em></p>
|
||||||
|
<p><%= f.text_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %></p>
|
||||||
|
<p><%= f.text_field :hours, :size => 6, :required => true %></p>
|
||||||
|
<p><%= f.text_field :comment, :size => 100 %></p>
|
||||||
|
<p><%= f.select :activity_id, (@activities.collect {|p| [p.name, p.id]}), :required => true %></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= submit_tag l(:button_save) %>
|
||||||
|
|
||||||
|
<% 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 %>
|
|
@ -0,0 +1,24 @@
|
||||||
|
class CreateTimeEntries < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
create_table :time_entries do |t|
|
||||||
|
t.column :project_id, :integer, :null => false
|
||||||
|
t.column :user_id, :integer, :null => false
|
||||||
|
t.column :issue_id, :integer
|
||||||
|
t.column :hours, :float, :null => false
|
||||||
|
t.column :comment, :string, :limit => 255
|
||||||
|
t.column :activity_id, :integer, :null => false
|
||||||
|
t.column :spent_on, :date, :null => false
|
||||||
|
t.column :tyear, :integer, :null => false
|
||||||
|
t.column :tmonth, :integer, :null => false
|
||||||
|
t.column :tweek, :integer, :null => false
|
||||||
|
t.column :created_on, :datetime, :null => false
|
||||||
|
t.column :updated_on, :datetime, :null => false
|
||||||
|
end
|
||||||
|
add_index :time_entries, [:project_id], :name => :time_entries_project_id
|
||||||
|
add_index :time_entries, [:issue_id], :name => :time_entries_issue_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
drop_table :time_entries
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
class AddTimelogPermissions < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
Permission.create :controller => "timelog", :action => "edit", :description => "button_log_time", :sort => 1520, :is_public => false, :mail_option => 0, :mail_enabled => 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
Permission.find_by_controller_and_action('timelog', 'edit').destroy
|
||||||
|
end
|
||||||
|
end
|
11
lang/de.yml
11
lang/de.yml
|
@ -143,6 +143,9 @@ field_comment: Kommentar
|
||||||
field_url: URL
|
field_url: URL
|
||||||
field_start_page: Hauptseite
|
field_start_page: Hauptseite
|
||||||
field_subproject: Subprojekt von
|
field_subproject: Subprojekt von
|
||||||
|
field_hours: Hours
|
||||||
|
field_activity: Activity
|
||||||
|
field_spent_on: Datum
|
||||||
|
|
||||||
setting_app_title: Applikation Titel
|
setting_app_title: Applikation Titel
|
||||||
setting_app_subtitle: Applikation Untertitel
|
setting_app_subtitle: Applikation Untertitel
|
||||||
|
@ -331,6 +334,10 @@ label_preview: Preview
|
||||||
label_feed_plural: Feeds
|
label_feed_plural: Feeds
|
||||||
label_changes_details: Details aller Änderungen
|
label_changes_details: Details aller Änderungen
|
||||||
label_issue_tracking: Tickets
|
label_issue_tracking: Tickets
|
||||||
|
label_spent_time: Spent time
|
||||||
|
label_f_hour: %.2f hour
|
||||||
|
label_f_hour_plural: %.2f hours
|
||||||
|
label_time_tracking: Time tracking
|
||||||
|
|
||||||
button_login: Einloggen
|
button_login: Einloggen
|
||||||
button_submit: OK
|
button_submit: OK
|
||||||
|
@ -355,6 +362,7 @@ button_back: Zurück
|
||||||
button_cancel: Abbrechen
|
button_cancel: Abbrechen
|
||||||
button_activate: Aktivieren
|
button_activate: Aktivieren
|
||||||
button_sort: Sortieren
|
button_sort: Sortieren
|
||||||
|
button_log_time: Log time
|
||||||
|
|
||||||
status_active: aktiv
|
status_active: aktiv
|
||||||
status_registered: angemeldet
|
status_registered: angemeldet
|
||||||
|
@ -392,6 +400,9 @@ default_priority_normal: Normal
|
||||||
default_priority_high: Hoch
|
default_priority_high: Hoch
|
||||||
default_priority_urgent: Dringend
|
default_priority_urgent: Dringend
|
||||||
default_priority_immediate: Sofort
|
default_priority_immediate: Sofort
|
||||||
|
default_activity_design: Design
|
||||||
|
default_activity_development: Development
|
||||||
|
|
||||||
enumeration_issue_priorities: Ticket-Prioritäten
|
enumeration_issue_priorities: Ticket-Prioritäten
|
||||||
enumeration_doc_categories: Dokumentenkategorien
|
enumeration_doc_categories: Dokumentenkategorien
|
||||||
|
enumeration_activities: Activities (time tracking)
|
||||||
|
|
11
lang/en.yml
11
lang/en.yml
|
@ -143,6 +143,9 @@ field_comment: Comment
|
||||||
field_url: URL
|
field_url: URL
|
||||||
field_start_page: Start page
|
field_start_page: Start page
|
||||||
field_subproject: Subproject
|
field_subproject: Subproject
|
||||||
|
field_hours: Hours
|
||||||
|
field_activity: Activity
|
||||||
|
field_spent_on: Date
|
||||||
|
|
||||||
setting_app_title: Application title
|
setting_app_title: Application title
|
||||||
setting_app_subtitle: Application subtitle
|
setting_app_subtitle: Application subtitle
|
||||||
|
@ -331,6 +334,10 @@ label_preview: Preview
|
||||||
label_feed_plural: Feeds
|
label_feed_plural: Feeds
|
||||||
label_changes_details: Details of all changes
|
label_changes_details: Details of all changes
|
||||||
label_issue_tracking: Issue tracking
|
label_issue_tracking: Issue tracking
|
||||||
|
label_spent_time: Spent time
|
||||||
|
label_f_hour: %.2f hour
|
||||||
|
label_f_hour_plural: %.2f hours
|
||||||
|
label_time_tracking: Time tracking
|
||||||
|
|
||||||
button_login: Login
|
button_login: Login
|
||||||
button_submit: Submit
|
button_submit: Submit
|
||||||
|
@ -355,6 +362,7 @@ button_back: Back
|
||||||
button_cancel: Cancel
|
button_cancel: Cancel
|
||||||
button_activate: Activate
|
button_activate: Activate
|
||||||
button_sort: Sort
|
button_sort: Sort
|
||||||
|
button_log_time: Log time
|
||||||
|
|
||||||
status_active: active
|
status_active: active
|
||||||
status_registered: registered
|
status_registered: registered
|
||||||
|
@ -392,6 +400,9 @@ default_priority_normal: Normal
|
||||||
default_priority_high: High
|
default_priority_high: High
|
||||||
default_priority_urgent: Urgent
|
default_priority_urgent: Urgent
|
||||||
default_priority_immediate: Immediate
|
default_priority_immediate: Immediate
|
||||||
|
default_activity_design: Design
|
||||||
|
default_activity_development: Development
|
||||||
|
|
||||||
enumeration_issue_priorities: Issue priorities
|
enumeration_issue_priorities: Issue priorities
|
||||||
enumeration_doc_categories: Document categories
|
enumeration_doc_categories: Document categories
|
||||||
|
enumeration_activities: Activities (time tracking)
|
||||||
|
|
11
lang/es.yml
11
lang/es.yml
|
@ -143,6 +143,9 @@ field_comment: Comentario
|
||||||
field_url: URL
|
field_url: URL
|
||||||
field_start_page: Página principal
|
field_start_page: Página principal
|
||||||
field_subproject: Proyecto secundario
|
field_subproject: Proyecto secundario
|
||||||
|
field_hours: Hours
|
||||||
|
field_activity: Activity
|
||||||
|
field_spent_on: Fecha
|
||||||
|
|
||||||
setting_app_title: Título del aplicación
|
setting_app_title: Título del aplicación
|
||||||
setting_app_subtitle: Subtítulo del aplicación
|
setting_app_subtitle: Subtítulo del aplicación
|
||||||
|
@ -331,6 +334,10 @@ label_preview: Previo
|
||||||
label_feed_plural: Feeds
|
label_feed_plural: Feeds
|
||||||
label_changes_details: Detalles de todos los cambios
|
label_changes_details: Detalles de todos los cambios
|
||||||
label_issue_tracking: Issue tracking
|
label_issue_tracking: Issue tracking
|
||||||
|
label_spent_time: Spent time
|
||||||
|
label_f_hour: %.2f hour
|
||||||
|
label_f_hour_plural: %.2f hours
|
||||||
|
label_time_tracking: Time tracking
|
||||||
|
|
||||||
button_login: Conexión
|
button_login: Conexión
|
||||||
button_submit: Someter
|
button_submit: Someter
|
||||||
|
@ -355,6 +362,7 @@ button_back: Atrás
|
||||||
button_cancel: Cancelar
|
button_cancel: Cancelar
|
||||||
button_activate: Activar
|
button_activate: Activar
|
||||||
button_sort: Clasificar
|
button_sort: Clasificar
|
||||||
|
button_log_time: Log time
|
||||||
|
|
||||||
status_active: active
|
status_active: active
|
||||||
status_registered: registered
|
status_registered: registered
|
||||||
|
@ -392,6 +400,9 @@ default_priority_normal: Normal
|
||||||
default_priority_high: Alto
|
default_priority_high: Alto
|
||||||
default_priority_urgent: Urgente
|
default_priority_urgent: Urgente
|
||||||
default_priority_immediate: Ahora
|
default_priority_immediate: Ahora
|
||||||
|
default_activity_design: Design
|
||||||
|
default_activity_development: Development
|
||||||
|
|
||||||
enumeration_issue_priorities: Prioridad de las peticiones
|
enumeration_issue_priorities: Prioridad de las peticiones
|
||||||
enumeration_doc_categories: Categorías del documento
|
enumeration_doc_categories: Categorías del documento
|
||||||
|
enumeration_activities: Activities (time tracking)
|
||||||
|
|
11
lang/fr.yml
11
lang/fr.yml
|
@ -143,6 +143,9 @@ field_comment: Commentaire
|
||||||
field_url: URL
|
field_url: URL
|
||||||
field_start_page: Page de démarrage
|
field_start_page: Page de démarrage
|
||||||
field_subproject: Sous-projet
|
field_subproject: Sous-projet
|
||||||
|
field_hours: Heures
|
||||||
|
field_activity: Activité
|
||||||
|
field_spent_on: Date
|
||||||
|
|
||||||
setting_app_title: Titre de l'application
|
setting_app_title: Titre de l'application
|
||||||
setting_app_subtitle: Sous-titre de l'application
|
setting_app_subtitle: Sous-titre de l'application
|
||||||
|
@ -331,6 +334,10 @@ label_preview: Prévisualisation
|
||||||
label_feed_plural: Flux RSS
|
label_feed_plural: Flux RSS
|
||||||
label_changes_details: Détails de tous les changements
|
label_changes_details: Détails de tous les changements
|
||||||
label_issue_tracking: Suivi des demandes
|
label_issue_tracking: Suivi des demandes
|
||||||
|
label_spent_time: Temps passé
|
||||||
|
label_f_hour: %.2f heure
|
||||||
|
label_f_hour_plural: %.2f heures
|
||||||
|
label_time_tracking: Suivi du temps
|
||||||
|
|
||||||
button_login: Connexion
|
button_login: Connexion
|
||||||
button_submit: Soumettre
|
button_submit: Soumettre
|
||||||
|
@ -355,6 +362,7 @@ button_back: Retour
|
||||||
button_cancel: Annuler
|
button_cancel: Annuler
|
||||||
button_activate: Activer
|
button_activate: Activer
|
||||||
button_sort: Trier
|
button_sort: Trier
|
||||||
|
button_log_time: Saisir temps
|
||||||
|
|
||||||
status_active: actif
|
status_active: actif
|
||||||
status_registered: enregistré
|
status_registered: enregistré
|
||||||
|
@ -392,6 +400,9 @@ default_priority_normal: Normal
|
||||||
default_priority_high: Haut
|
default_priority_high: Haut
|
||||||
default_priority_urgent: Urgent
|
default_priority_urgent: Urgent
|
||||||
default_priority_immediate: Immédiat
|
default_priority_immediate: Immédiat
|
||||||
|
default_activity_design: Conception
|
||||||
|
default_activity_development: Développement
|
||||||
|
|
||||||
enumeration_issue_priorities: Priorités des demandes
|
enumeration_issue_priorities: Priorités des demandes
|
||||||
enumeration_doc_categories: Catégories des documents
|
enumeration_doc_categories: Catégories des documents
|
||||||
|
enumeration_activities: Activités (suivi du temps)
|
||||||
|
|
11
lang/it.yml
11
lang/it.yml
|
@ -143,6 +143,9 @@ field_comment: Commento
|
||||||
field_url: URL
|
field_url: URL
|
||||||
field_start_page: Pagina principale
|
field_start_page: Pagina principale
|
||||||
field_subproject: Sottoprogetto
|
field_subproject: Sottoprogetto
|
||||||
|
field_hours: Hours
|
||||||
|
field_activity: Activity
|
||||||
|
field_spent_on: Data
|
||||||
|
|
||||||
setting_app_title: Titolo applicazione
|
setting_app_title: Titolo applicazione
|
||||||
setting_app_subtitle: Sottotitolo applicazione
|
setting_app_subtitle: Sottotitolo applicazione
|
||||||
|
@ -331,6 +334,10 @@ label_preview: Previsione
|
||||||
label_feed_plural: Feeds
|
label_feed_plural: Feeds
|
||||||
label_changes_details: Particolari di tutti i cambiamenti
|
label_changes_details: Particolari di tutti i cambiamenti
|
||||||
label_issue_tracking: Issue tracking
|
label_issue_tracking: Issue tracking
|
||||||
|
label_spent_time: Spent time
|
||||||
|
label_f_hour: %.2f hour
|
||||||
|
label_f_hour_plural: %.2f hours
|
||||||
|
label_time_tracking: Time tracking
|
||||||
|
|
||||||
button_login: Login
|
button_login: Login
|
||||||
button_submit: Invia
|
button_submit: Invia
|
||||||
|
@ -355,6 +362,7 @@ button_back: Indietro
|
||||||
button_cancel: Annulla
|
button_cancel: Annulla
|
||||||
button_activate: Attiva
|
button_activate: Attiva
|
||||||
button_sort: Ordina
|
button_sort: Ordina
|
||||||
|
button_log_time: Log time
|
||||||
|
|
||||||
status_active: active
|
status_active: active
|
||||||
status_registered: registered
|
status_registered: registered
|
||||||
|
@ -392,6 +400,9 @@ default_priority_normal: Normale
|
||||||
default_priority_high: Alta
|
default_priority_high: Alta
|
||||||
default_priority_urgent: Urgente
|
default_priority_urgent: Urgente
|
||||||
default_priority_immediate: Immediata
|
default_priority_immediate: Immediata
|
||||||
|
default_activity_design: Design
|
||||||
|
default_activity_development: Development
|
||||||
|
|
||||||
enumeration_issue_priorities: Priorità contesti
|
enumeration_issue_priorities: Priorità contesti
|
||||||
enumeration_doc_categories: Categorie di documenti
|
enumeration_doc_categories: Categorie di documenti
|
||||||
|
enumeration_activities: Activities (time tracking)
|
||||||
|
|
11
lang/ja.yml
11
lang/ja.yml
|
@ -144,6 +144,9 @@ field_comment: コメント
|
||||||
field_url: URL
|
field_url: URL
|
||||||
field_start_page: メインページ
|
field_start_page: メインページ
|
||||||
field_subproject: サブプロジェクト
|
field_subproject: サブプロジェクト
|
||||||
|
field_hours: Hours
|
||||||
|
field_activity: Activity
|
||||||
|
field_spent_on: 日付
|
||||||
|
|
||||||
setting_app_title: アプリケーションのタイトル
|
setting_app_title: アプリケーションのタイトル
|
||||||
setting_app_subtitle: アプリケーションのサブタイトル
|
setting_app_subtitle: アプリケーションのサブタイトル
|
||||||
|
@ -332,6 +335,10 @@ label_preview: 下検分
|
||||||
label_feed_plural: Feeds
|
label_feed_plural: Feeds
|
||||||
label_changes_details: Details of all changes
|
label_changes_details: Details of all changes
|
||||||
label_issue_tracking: Issue tracking
|
label_issue_tracking: Issue tracking
|
||||||
|
label_spent_time: Spent time
|
||||||
|
label_f_hour: %.2f hour
|
||||||
|
label_f_hour_plural: %.2f hours
|
||||||
|
label_time_tracking: Time tracking
|
||||||
|
|
||||||
button_login: ログイン
|
button_login: ログイン
|
||||||
button_submit: 変更
|
button_submit: 変更
|
||||||
|
@ -356,6 +363,7 @@ button_back: 戻る
|
||||||
button_cancel: キャンセル
|
button_cancel: キャンセル
|
||||||
button_activate: 有効にする
|
button_activate: 有効にする
|
||||||
button_sort: ソート
|
button_sort: ソート
|
||||||
|
button_log_time: Log time
|
||||||
|
|
||||||
status_active: active
|
status_active: active
|
||||||
status_registered: registered
|
status_registered: registered
|
||||||
|
@ -393,6 +401,9 @@ default_priority_normal: 通常
|
||||||
default_priority_high: 高め
|
default_priority_high: 高め
|
||||||
default_priority_urgent: 急いで
|
default_priority_urgent: 急いで
|
||||||
default_priority_immediate: 今すぐ
|
default_priority_immediate: 今すぐ
|
||||||
|
default_activity_design: Design
|
||||||
|
default_activity_development: Development
|
||||||
|
|
||||||
enumeration_issue_priorities: 問題の優先度
|
enumeration_issue_priorities: 問題の優先度
|
||||||
enumeration_doc_categories: 文書カテゴリ
|
enumeration_doc_categories: 文書カテゴリ
|
||||||
|
enumeration_activities: Activities (time tracking)
|
||||||
|
|
|
@ -39,7 +39,7 @@ begin
|
||||||
manager.permissions = Permission.find(:all, :conditions => ["is_public=?", false])
|
manager.permissions = Permission.find(:all, :conditions => ["is_public=?", false])
|
||||||
|
|
||||||
developper = Role.create :name => l(:default_role_developper), :position => 2
|
developper = Role.create :name => l(:default_role_developper), :position => 2
|
||||||
perms = [150, 320, 321, 322, 420, 421, 422, 1050, 1060, 1070, 1075, 1130, 1220, 1221, 1222, 1223, 1224, 1320, 1322, 1061, 1057]
|
perms = [150, 320, 321, 322, 420, 421, 422, 1050, 1060, 1070, 1075, 1130, 1220, 1221, 1222, 1223, 1224, 1320, 1322, 1061, 1057, 1520]
|
||||||
developper.permissions = Permission.find(:all, :conditions => ["sort IN (#{perms.join(',')})"])
|
developper.permissions = Permission.find(:all, :conditions => ["sort IN (#{perms.join(',')})"])
|
||||||
|
|
||||||
reporter = Role.create :name => l(:default_role_reporter), :position => 3
|
reporter = Role.create :name => l(:default_role_reporter), :position => 3
|
||||||
|
@ -88,12 +88,16 @@ begin
|
||||||
# enumerations
|
# enumerations
|
||||||
Enumeration.create(:opt => "DCAT", :name => l(:default_doc_category_user))
|
Enumeration.create(:opt => "DCAT", :name => l(:default_doc_category_user))
|
||||||
Enumeration.create(:opt => "DCAT", :name => l(:default_doc_category_tech))
|
Enumeration.create(:opt => "DCAT", :name => l(:default_doc_category_tech))
|
||||||
|
|
||||||
Enumeration.create(:opt => "IPRI", :name => l(:default_priority_low))
|
Enumeration.create(:opt => "IPRI", :name => l(:default_priority_low))
|
||||||
Enumeration.create(:opt => "IPRI", :name => l(:default_priority_normal))
|
Enumeration.create(:opt => "IPRI", :name => l(:default_priority_normal))
|
||||||
Enumeration.create(:opt => "IPRI", :name => l(:default_priority_high))
|
Enumeration.create(:opt => "IPRI", :name => l(:default_priority_high))
|
||||||
Enumeration.create(:opt => "IPRI", :name => l(:default_priority_urgent))
|
Enumeration.create(:opt => "IPRI", :name => l(:default_priority_urgent))
|
||||||
Enumeration.create(:opt => "IPRI", :name => l(:default_priority_immediate))
|
Enumeration.create(:opt => "IPRI", :name => l(:default_priority_immediate))
|
||||||
|
|
||||||
|
Enumeration.create(:opt => "ACTI", :name => l(:default_activity_design))
|
||||||
|
Enumeration.create(:opt => "ACTI", :name => l(:default_activity_development))
|
||||||
|
|
||||||
rescue => error
|
rescue => error
|
||||||
puts "Error: " + error
|
puts "Error: " + error
|
||||||
puts "Default configuration data can't be loaded."
|
puts "Default configuration data can't be loaded."
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 993 B |
|
@ -155,6 +155,7 @@ vertical-align: middle;
|
||||||
.icon-index { background-image: url(../images/index.png); }
|
.icon-index { background-image: url(../images/index.png); }
|
||||||
.icon-history { background-image: url(../images/history.png); }
|
.icon-history { background-image: url(../images/history.png); }
|
||||||
.icon-feed { background-image: url(../images/feed.png); }
|
.icon-feed { background-image: url(../images/feed.png); }
|
||||||
|
.icon-time { background-image: url(../images/time.png); }
|
||||||
|
|
||||||
.icon22-projects { background-image: url(../images/22x22/projects.png); }
|
.icon22-projects { background-image: url(../images/22x22/projects.png); }
|
||||||
.icon22-users { background-image: url(../images/22x22/users.png); }
|
.icon22-users { background-image: url(../images/22x22/users.png); }
|
||||||
|
@ -542,7 +543,7 @@ font-size: 1em;
|
||||||
/***** Tooltips ******/
|
/***** Tooltips ******/
|
||||||
.tooltip{position:relative;z-index:24;}
|
.tooltip{position:relative;z-index:24;}
|
||||||
.tooltip:hover{z-index:25;color:#000;}
|
.tooltip:hover{z-index:25;color:#000;}
|
||||||
.tooltip span.tip{display: none}
|
.tooltip span.tip{display: none; text-align:left;}
|
||||||
|
|
||||||
div.tooltip:hover span.tip{
|
div.tooltip:hover span.tip{
|
||||||
display:block;
|
display:block;
|
||||||
|
|
Loading…
Reference in New Issue