Commit 8d54d970 authored by Jean-Philippe Lang's avatar Jean-Philippe Lang

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
parent 7cf2d889
...@@ -57,6 +57,7 @@ class ReportsController < ApplicationController ...@@ -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
......
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 ...@@ -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
......
module TimelogHelper
end
...@@ -24,7 +24,8 @@ class Enumeration < ActiveRecord::Base ...@@ -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 ...@@ -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 ...@@ -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
...@@ -91,6 +91,10 @@ class Issue < ActiveRecord::Base ...@@ -91,6 +91,10 @@ class Issue < ActiveRecord::Base
self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value } self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
@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
......
...@@ -30,7 +30,8 @@ class Permission < ActiveRecord::Base ...@@ -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 ...@@ -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
......
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 @@ ...@@ -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 %> ...@@ -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>
......
<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 @@ ...@@ -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)%>&nbsp;&nbsp;<%= link_to image_tag('zoom_in.png'), :detail => 'tracker' %></h3> <h3><%=l(:field_tracker)%>&nbsp;&nbsp;<%= link_to image_tag('zoom_in.png'), :detail => 'tracker' %></h3>
......
<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 %>
\ No newline at end of file
<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 %>
\ No newline at end of file
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
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
...@@ -143,6 +143,9 @@ field_comment: Kommentar ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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)
...@@ -143,6 +143,9 @@ field_comment: Comment ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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)
...@@ -143,6 +143,9 @@ field_comment: Comentario ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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)
...@@ -143,6 +143,9 @@ field_comment: Commentaire ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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)
...@@ -143,6 +143,9 @@ field_comment: Commento ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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)
...@@ -144,6 +144,9 @@ field_comment: コメント ...@@ -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: 下検分 ...@@ -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: 戻る ...@@ -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: 通常 ...@@ -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 ...@@ -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 ...@@ -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."
......
...@@ -155,6 +155,7 @@ vertical-align: middle; ...@@ -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; ...@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment