]> source.dussan.org Git - redmine.git/commitdiff
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Sat, 5 May 2007 13:22:27 +0000 (13:22 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Sat, 5 May 2007 13:22:27 +0000 (13:22 +0000)
* relates to: do nothing special. Just to know that the 2 issues are related...
* duplicates: will close the related issue with the same status when closing the issue (not implemented yet)
* blocks: will require to close the blocking issue before closing the blocked issue (not implemented yet)
* precedes (end to start relation): start date of the related issue depends on the due date of the preceding issue (implemented). A delay can be set so that the related issue can only start n days after the end of the preceding issue. When setting dates for an issue, dates of all downstream issues are set according to these relations.

To set a relation, the 2 issues have to belong to the same project (may change in the future). So if an issue is moved to another project, all its relations are removed.
Circular dependencies are checked when creating a relation.

git-svn-id: http://redmine.rubyforge.org/svn/trunk@506 e93f8b46-1217-0410-a6f0-8f06a7374b81

22 files changed:
app/controllers/issue_relations_controller.rb [new file with mode: 0644]
app/controllers/issues_controller.rb
app/controllers/projects_controller.rb
app/helpers/issue_relations_helper.rb [new file with mode: 0644]
app/models/issue.rb
app/models/issue_relation.rb [new file with mode: 0644]
app/views/issue_relations/_form.rhtml [new file with mode: 0644]
app/views/issues/_relations.rhtml [new file with mode: 0644]
app/views/issues/show.rhtml
config/routes.rb
db/migrate/042_create_issue_relations.rb [new file with mode: 0644]
db/migrate/043_add_relations_permissions.rb [new file with mode: 0644]
lang/bg.yml
lang/de.yml
lang/en.yml
lang/es.yml
lang/fr.yml
lang/it.yml
lang/ja.yml
lang/pt.yml
lang/zh.yml
public/javascripts/application.js

diff --git a/app/controllers/issue_relations_controller.rb b/app/controllers/issue_relations_controller.rb
new file mode 100644 (file)
index 0000000..cb0ad55
--- /dev/null
@@ -0,0 +1,59 @@
+# redMine - project management software
+# Copyright (C) 2006-2007  Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+class IssueRelationsController < ApplicationController
+  layout 'base'
+  before_filter :find_project, :authorize
+  
+  def new
+    @relation = IssueRelation.new(params[:relation])
+    @relation.issue_from = @issue
+    @relation.save if request.post?
+    respond_to do |format|
+      format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
+      format.js do
+        render :update do |page|
+          page.replace_html "relations", :partial => 'issues/relations'
+          if @relation.errors.empty?
+            page << "$('relation_delay').value = ''"
+            page << "$('relation_issue_to_id').value = ''"
+          end
+        end
+      end
+    end
+  end
+  
+  def destroy
+    relation = IssueRelation.find(params[:id])
+    if request.post? && @issue.relations.include?(relation)
+      relation.destroy
+      @issue.reload
+    end
+    respond_to do |format|
+      format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
+      format.js { render(:update) {|page| page.replace_html "relations", :partial => 'issues/relations'} }
+    end
+  end
+  
+private
+  def find_project
+    @issue = Issue.find(params[:issue_id])
+    @project = @issue.project
+  rescue ActiveRecord::RecordNotFound
+    render_404
+  end
+end
index be1b8c003771bfbecb9c588df04dc382ff3c16c0..99dc687f869de9210968f7e0ae19dc03870f00be 100644 (file)
@@ -23,6 +23,8 @@ class IssuesController < ApplicationController
   include CustomFieldsHelper
   helper :ifpdf
   include IfpdfHelper
+  helper :issue_relations
+  include IssueRelationsHelper
 
   def show
     @status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
index 6d8c3863e55f4501c4c495e0454176dc4bd31e10..d3a71478b2a59a75aa632210f52a9470a160732a 100644 (file)
@@ -364,6 +364,9 @@ class ProjectsController < ApplicationController
         unless i.project_id == new_project.id
           i.category = nil 
           i.fixed_version = nil
+          # delete issue relations
+          i.relations_from.clear
+          i.relations_to.clear
         end
         # move the issue
         i.project = new_project
diff --git a/app/helpers/issue_relations_helper.rb b/app/helpers/issue_relations_helper.rb
new file mode 100644 (file)
index 0000000..377059d
--- /dev/null
@@ -0,0 +1,23 @@
+# redMine - project management software
+# Copyright (C) 2006-2007  Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+module IssueRelationsHelper
+  def collection_for_relation_type_select
+    values = IssueRelation::TYPES
+    values.keys.sort{|x,y| values[x][:order] <=> values[y][:order]}.collect{|k| [l(values[k][:name]), k]}
+  end
+end
index 72a953f62d10676e4241ba188781d71a5268c623..6dc812ce44bb6f9d2cd5c0bb736cfa64e9f66a14 100644 (file)
@@ -1,5 +1,5 @@
 # redMine - project management software
-# Copyright (C) 2006  Jean-Philippe Lang
+# Copyright (C) 2006-2007  Jean-Philippe Lang
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -16,7 +16,6 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 class Issue < ActiveRecord::Base
-
   belongs_to :project
   belongs_to :tracker
   belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
@@ -33,6 +32,9 @@ class Issue < ActiveRecord::Base
   has_many :custom_fields, :through => :custom_values
   has_and_belongs_to_many :changesets, :order => "revision ASC"
   
+  has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all
+  has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
+  
   acts_as_watchable
   
   validates_presence_of :subject, :description, :priority, :tracker, :author, :status
@@ -52,13 +54,13 @@ class Issue < ActiveRecord::Base
     if self.due_date and self.start_date and self.due_date < self.start_date
       errors.add :due_date, :activerecord_error_greater_than_start_date
     end
+    
+    if start_date && soonest_start && start_date < soonest_start
+      errors.add :start_date, :activerecord_error_invalid
+    end
   end
-
-  #def before_create
-  #  build_history
-  #end
   
-  def before_save
+  def before_save  
     if @current_journal
       # attributes changes
       (Issue.column_names - %w(id description)).each {|c|
@@ -78,6 +80,10 @@ class Issue < ActiveRecord::Base
     end
   end
   
+  def after_save
+    relations_from.each(&:set_issue_to_dates)
+  end  
+  
   def long_id
     "%05d" % self.id
   end
@@ -98,12 +104,25 @@ class Issue < ActiveRecord::Base
   def spent_hours
     @spent_hours ||= time_entries.sum(:hours) || 0
   end
-
-private
-  # Creates an history for the issue
-  #def build_history
-  #  @history = self.histories.build
-  #  @history.status = self.status
-  #  @history.author = self.author
-  #end
+  
+  def relations
+    (relations_from + relations_to).sort
+  end
+  
+  def all_dependent_issues
+    dependencies = []
+    relations_from.each do |relation|
+      dependencies << relation.issue_to
+      dependencies += relation.issue_to.all_dependent_issues
+    end
+    dependencies
+  end
+  
+  def duration
+    (start_date && due_date) ? due_date - start_date : 0
+  end
+  
+  def soonest_start
+    @soonest_start ||= relations_to.collect{|relation| relation.successor_soonest_start}.compact.min
+  end
 end
diff --git a/app/models/issue_relation.rb b/app/models/issue_relation.rb
new file mode 100644 (file)
index 0000000..05ea520
--- /dev/null
@@ -0,0 +1,79 @@
+# redMine - project management software
+# Copyright (C) 2006-2007  Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+class IssueRelation < ActiveRecord::Base
+  belongs_to :issue_from, :class_name => 'Issue', :foreign_key => 'issue_from_id'
+  belongs_to :issue_to, :class_name => 'Issue', :foreign_key => 'issue_to_id'
+  
+  TYPE_RELATES      = "relates"
+  TYPE_DUPLICATES   = "duplicates"
+  TYPE_BLOCKS       = "blocks"
+  TYPE_PRECEDES     = "precedes"
+  
+  TYPES = { TYPE_RELATES =>     { :name => :label_relates_to, :sym_name => :label_relates_to, :order => 1 },
+            TYPE_DUPLICATES =>  { :name => :label_duplicates, :sym_name => :label_duplicates, :order => 2 },
+            TYPE_BLOCKS =>      { :name => :label_blocks, :sym_name => :label_blocked_by, :order => 3 },
+            TYPE_PRECEDES =>    { :name => :label_precedes, :sym_name => :label_follows, :order => 4 },
+          }.freeze
+  
+  validates_presence_of :issue_from, :issue_to, :relation_type
+  validates_inclusion_of :relation_type, :in => TYPES.keys
+  validates_numericality_of :delay, :allow_nil => true
+  validates_uniqueness_of :issue_to_id, :scope => :issue_from_id
+  
+  def validate
+    if issue_from && issue_to
+      errors.add :issue_to_id, :activerecord_error_invalid if issue_from_id == issue_to_id
+      errors.add :issue_to_id, :activerecord_error_not_same_project unless issue_from.project_id == issue_to.project_id
+      errors.add_to_base :activerecord_error_circular_dependency if issue_to.all_dependent_issues.include? issue_from
+    end
+  end
+  
+  def other_issue(issue)
+    (self.issue_from_id == issue.id) ? issue_to : issue_from
+  end
+  
+  def label_for(issue)
+    TYPES[relation_type] ? TYPES[relation_type][(self.issue_from_id == issue.id) ? :name : :sym_name] : :unknow
+  end
+  
+  def before_save
+    if TYPE_PRECEDES == relation_type
+      self.delay ||= 0
+    else
+      self.delay = nil
+    end
+    set_issue_to_dates
+  end
+  
+  def set_issue_to_dates
+    soonest_start = self.successor_soonest_start
+    if soonest_start && (!issue_to.start_date || issue_to.start_date < soonest_start)
+      issue_to.start_date, issue_to.due_date = successor_soonest_start, successor_soonest_start + issue_to.duration
+      issue_to.save
+    end
+  end
+  
+  def successor_soonest_start
+    return nil unless (TYPE_PRECEDES == self.relation_type) && (issue_from.start_date || issue_from.due_date)
+    (issue_from.due_date || issue_from.start_date) + 1 + delay
+  end
+  
+  def <=>(relation)
+    TYPES[self.relation_type][:order] <=> TYPES[relation.relation_type][:order]
+  end
+end
diff --git a/app/views/issue_relations/_form.rhtml b/app/views/issue_relations/_form.rhtml
new file mode 100644 (file)
index 0000000..8b514dc
--- /dev/null
@@ -0,0 +1,10 @@
+<%= error_messages_for 'relation' %>
+
+<p><%= f.select :relation_type, collection_for_relation_type_select, {}, :onchange => "setPredecessorFieldsVisibility();" %>
+<%= l(:label_issue) %> #<%= f.text_field :issue_to_id, :size => 6 %>
+<span id="predecessor_fields" style="display:none;">
+<%= l(:field_delay) %>: <%= f.text_field :delay, :size => 3 %> <%= l(:label_day_plural) %>
+</span>
+<%= submit_tag l(:button_add) %></p>
+
+<%= javascript_tag "setPredecessorFieldsVisibility();" %>
diff --git a/app/views/issues/_relations.rhtml b/app/views/issues/_relations.rhtml
new file mode 100644 (file)
index 0000000..f817d38
--- /dev/null
@@ -0,0 +1,22 @@
+<h3><%=l(:label_related_issues)%></h3>
+
+<table style="width:100%">
+<% @issue.relations.each do |relation| %>
+<tr>
+<td><%= l(relation.label_for(@issue)) %> <%= "(#{lwr(:actionview_datehelper_time_in_words_day, relation.delay)})" if relation.delay && relation.delay != 0 %> <%= link_to_issue relation.other_issue(@issue) %></td>
+<td><%=h relation.other_issue(@issue).subject %></td>
+<td><div class="square" style="background:#<%= relation.other_issue(@issue).status.html_color %>;"></div> <%= relation.other_issue(@issue).status.name %></td>
+<td><%= format_date(relation.other_issue(@issue).start_date) %></td>
+<td><%= format_date(relation.other_issue(@issue).due_date) %></td>
+<td><%= link_to_remote image_tag('delete.png'), { :url => {:controller => 'issue_relations', :action => 'destroy', :issue_id => @issue, :id => relation},                                              
+                                                  :method => :post
+                                                }, :title => l(:label_relation_delete) %></td>
+</tr>
+<% end %>
+</table>
+
+<% if authorize_for('issue_relations', 'new') %>&nbsp;  
+  <% remote_form_for(:relation, @relation, :url => {:controller => 'issue_relations', :action => 'new', :issue_id => @issue}, :method => :post) do |f| %>
+    <%= render :partial => 'issue_relations/form', :locals => {:f => f}%>
+  <% end %>
+<% end %>
index 2eb01f094639b1c451b0cf77531f69c16a411230..d7d9bcf6d33c59ebcb24cb0b07848511ce7f8366 100644 (file)
@@ -81,6 +81,12 @@ end %>
 &nbsp;
 </div>
 
+<% if authorize_for('issue_relations', 'new') || @issue.relations.any? %>
+<div id="relations" class="box">
+<%= render :partial => 'relations' %>
+</div>
+<% end %>
+
 <div id="history" class="box">
 <h3><%=l(:label_history)%>
 <% if @journals_count > @journals.length %>(<%= l(:label_last_changes, @journals.length) %>)<% end %></h3>
index dfa2a5df21542be3933cd260684491400cdb96a9..8e2670a995ecd50584e2bc2fd16b594b2c6f57f3 100644 (file)
@@ -15,6 +15,8 @@ ActionController::Routing::Routes.draw do |map|
   map.connect 'help/:ctrl/:page', :controller => 'help'\r
   #map.connect ':controller/:action/:id/:sort_key/:sort_order'\r
   
+  map.connect 'issues/:issue_id/relations/:action/:id', :controller => 'issue_relations'
+  
   # Allow downloading Web Service WSDL as a file with an extension
   # instead of a file named 'wsdl'
   map.connect ':controller/service.wsdl', :action => 'wsdl'
diff --git a/db/migrate/042_create_issue_relations.rb b/db/migrate/042_create_issue_relations.rb
new file mode 100644 (file)
index 0000000..802c124
--- /dev/null
@@ -0,0 +1,14 @@
+class CreateIssueRelations < ActiveRecord::Migration
+  def self.up
+    create_table :issue_relations do |t|
+      t.column :issue_from_id, :integer, :null => false
+      t.column :issue_to_id, :integer, :null => false
+      t.column :relation_type, :string, :default => "", :null => false
+      t.column :delay, :integer
+    end
+  end
+
+  def self.down
+    drop_table :issue_relations
+  end
+end
diff --git a/db/migrate/043_add_relations_permissions.rb b/db/migrate/043_add_relations_permissions.rb
new file mode 100644 (file)
index 0000000..3f1da8f
--- /dev/null
@@ -0,0 +1,11 @@
+class AddRelationsPermissions < ActiveRecord::Migration
+  def self.up
+    Permission.create :controller => "issue_relations", :action => "new", :description => "label_relation_new", :sort => 1080, :is_public => false, :mail_option => 0, :mail_enabled => 0
+    Permission.create :controller => "issue_relations", :action => "destroy", :description => "label_relation_delete", :sort => 1085, :is_public => false, :mail_option => 0, :mail_enabled => 0
+  end
+
+  def self.down
+    Permission.find_by_controller_and_action("issue_relations", "new").destroy
+    Permission.find_by_controller_and_action("issue_relations", "destroy").destroy
+  end
+end
index 41b6c6d8856ec0a029c2a6f46478420bfe958d22..6041f71b34e2861a69198e9c18a83875ccd63a0d 100644 (file)
@@ -33,6 +33,8 @@ activerecord_error_taken: вече съществува
 activerecord_error_not_a_number: не е число
 activerecord_error_not_a_date: е невалидна дата
 activerecord_error_greater_than_start_date: трябва да е след началната дата
+activerecord_error_not_same_project: doesn't belong to the same project
+activerecord_error_circular_dependency: This relation would create a circular dependency
 
 general_fmt_age: %d yr
 general_fmt_age_plural: %d yrs
@@ -149,6 +151,8 @@ field_activity: Дейност
 field_spent_on: Дата
 field_identifier: Идентификатор
 field_is_filter: Използва се за филтър
+field_issue_to_id: Related issue
+field_delay: Delay
 
 setting_app_title: Заглавие
 setting_app_subtitle: Описание
@@ -364,6 +368,18 @@ label_watched_issues: Наблюдавани задачи
 label_related_issues: Свързани задачи
 label_applied_status: Промени статуса на
 label_loading: Зареждане...
+label_relation_new: New relation
+label_relation_delete: Delete relation
+label_relates_to: related tp
+label_duplicates: duplicates
+label_blocks: blocks
+label_blocked_by: blocked by
+label_precedes: precedes
+label_follows: follows
+label_end_to_start: start to end
+label_end_to_end: end to end
+label_start_to_start: start to start
+label_start_to_end: start to end
 
 button_login: Вход
 button_submit: Изпращане
index efd5e38b624de5bf9523de3d9656cde9961512a5..35e4328cc08a22132c582d402e6c8b944e0bf775 100644 (file)
@@ -33,6 +33,8 @@ activerecord_error_taken: ist bereits vergeben
 activerecord_error_not_a_number: ist keine Zahl
 activerecord_error_not_a_date: ist kein gültiges Datum
 activerecord_error_greater_than_start_date: muss größer als Anfangsdatum sein
+activerecord_error_not_same_project: doesn't belong to the same project
+activerecord_error_circular_dependency: This relation would create a circular dependency
 
 general_fmt_age: %d Jahr
 general_fmt_age_plural: %d Jahre
@@ -149,6 +151,8 @@ field_activity: Aktivität
 field_spent_on: Datum
 field_identifier: Identifier
 field_is_filter: Used as a filter
+field_issue_to_id: Related issue
+field_delay: Delay
 
 setting_app_title: Applikation Titel
 setting_app_subtitle: Applikation Untertitel
@@ -364,6 +368,18 @@ label_watched_issues: Watched issues
 label_related_issues: Related issues
 label_applied_status: Applied status
 label_loading: Loading...
+label_relation_new: New relation
+label_relation_delete: Delete relation
+label_relates_to: related tp
+label_duplicates: duplicates
+label_blocks: blocks
+label_blocked_by: blocked by
+label_precedes: precedes
+label_follows: follows
+label_end_to_start: start to end
+label_end_to_end: end to end
+label_start_to_start: start to start
+label_start_to_end: start to end
 
 button_login: Einloggen
 button_submit: OK
index 7fcb2b14b1140be7d12dc35c43c3e3bb99b26141..fadcaad3fd15708e2141cca441ce851899276c5b 100644 (file)
@@ -33,6 +33,8 @@ activerecord_error_taken: has already been taken
 activerecord_error_not_a_number: is not a number
 activerecord_error_not_a_date: is not a valid date
 activerecord_error_greater_than_start_date: must be greater than start date
+activerecord_error_not_same_project: doesn't belong to the same project
+activerecord_error_circular_dependency: This relation would create a circular dependency
 
 general_fmt_age: %d yr
 general_fmt_age_plural: %d yrs
@@ -149,6 +151,8 @@ field_activity: Activity
 field_spent_on: Date
 field_identifier: Identifier
 field_is_filter: Used as a filter
+field_issue_to_id: Related issue
+field_delay: Delay
 
 setting_app_title: Application title
 setting_app_subtitle: Application subtitle
@@ -364,6 +368,18 @@ label_watched_issues: Watched issues
 label_related_issues: Related issues
 label_applied_status: Applied status
 label_loading: Loading...
+label_relation_new: New relation
+label_relation_delete: Delete relation
+label_relates_to: related tp
+label_duplicates: duplicates
+label_blocks: blocks
+label_blocked_by: blocked by
+label_precedes: precedes
+label_follows: follows
+label_end_to_start: start to end
+label_end_to_end: end to end
+label_start_to_start: start to start
+label_start_to_end: start to end
 
 button_login: Login
 button_submit: Submit
index 806c8d4624bb5f1d279996d149d2b155e3471d0e..e6c9002e7fe6874e034eed6e9ba8cf82473fd2bd 100644 (file)
@@ -33,6 +33,8 @@ activerecord_error_taken: has already been taken
 activerecord_error_not_a_number: is not a number
 activerecord_error_not_a_date: no es una fecha válida
 activerecord_error_greater_than_start_date: debe ser la fecha mayor que del comienzo
+activerecord_error_not_same_project: doesn't belong to the same project
+activerecord_error_circular_dependency: This relation would create a circular dependency
 
 general_fmt_age: %d año
 general_fmt_age_plural: %d años
@@ -149,6 +151,8 @@ field_activity: Activity
 field_spent_on: Fecha
 field_identifier: Identifier
 field_is_filter: Used as a filter
+field_issue_to_id: Related issue
+field_delay: Delay
 
 setting_app_title: Título del aplicación
 setting_app_subtitle: Subtítulo del aplicación
@@ -364,6 +368,18 @@ label_watched_issues: Watched issues
 label_related_issues: Related issues
 label_applied_status: Applied status
 label_loading: Loading...
+label_relation_new: New relation
+label_relation_delete: Delete relation
+label_relates_to: related tp
+label_duplicates: duplicates
+label_blocks: blocks
+label_blocked_by: blocked by
+label_precedes: precedes
+label_follows: follows
+label_end_to_start: start to end
+label_end_to_end: end to end
+label_start_to_start: start to start
+label_start_to_end: start to end
 
 button_login: Conexión
 button_submit: Someter
index 8423ba93b7e85e16c44047ef952f3f9b658c583b..394417ac9994313d11877c5889f138b4dd77979c 100644 (file)
@@ -1,4 +1,4 @@
-_gloc_rule_default: '|n| n<=1 ? "" : "_plural" '
+_gloc_rule_default: '|n| n==1 ? "" : "_plural" '
 
 actionview_datehelper_select_day_prefix:
 actionview_datehelper_select_month_names: Janvier,Février,Mars,Avril,Mai,Juin,Juillet,Août,Septembre,Octobre,Novembre,Décembre
@@ -33,6 +33,8 @@ activerecord_error_taken: est déjà utilisé
 activerecord_error_not_a_number: n'est pas un nombre
 activerecord_error_not_a_date: n'est pas une date valide
 activerecord_error_greater_than_start_date: doit être postérieur à la date de début
+activerecord_error_not_same_project: n'appartient pas au même projet
+activerecord_error_circular_dependency: Cette relation créerait une dépendance circulaire
 
 general_fmt_age: %d an
 general_fmt_age_plural: %d ans
@@ -149,6 +151,8 @@ field_activity: Activité
 field_spent_on: Date
 field_identifier: Identifiant
 field_is_filter: Utilisé comme filtre
+field_issue_to_id: Demande liée
+field_delay: Retard
 
 setting_app_title: Titre de l'application
 setting_app_subtitle: Sous-titre de l'application
@@ -364,6 +368,18 @@ label_watched_issues: Demandes surveillées
 label_related_issues: Demandes liées
 label_applied_status: Statut appliqué
 label_loading: Chargement...
+label_relation_new: Nouvelle relation
+label_relation_delete: Supprimer la relation
+label_relates_to: lié à
+label_duplicates: doublon de
+label_blocks: bloque
+label_blocked_by: bloqué par
+label_precedes: précède
+label_follows: suit
+label_end_to_start: début à fin
+label_end_to_end: fin à fin
+label_start_to_start: début à début
+label_start_to_end: début à fin
 
 button_login: Connexion
 button_submit: Soumettre
index 0c48ee20e5f06fd60e09723e30ad562e6b4e48dc..2deb091153dfc07bd4937a5e3e8bd03c3552f8fe 100644 (file)
@@ -33,6 +33,8 @@ activerecord_error_taken: e' gia' stato/a preso/a
 activerecord_error_not_a_number: non e' un numero
 activerecord_error_not_a_date: non e' una data valida
 activerecord_error_greater_than_start_date: deve essere maggiore della data di partenza
+activerecord_error_not_same_project: doesn't belong to the same project
+activerecord_error_circular_dependency: This relation would create a circular dependency
 
 general_fmt_age: %d yr
 general_fmt_age_plural: %d yrs
@@ -149,6 +151,8 @@ field_activity: Activity
 field_spent_on: Data
 field_identifier: Identifier
 field_is_filter: Used as a filter
+field_issue_to_id: Related issue
+field_delay: Delay
 
 setting_app_title: Titolo applicazione
 setting_app_subtitle: Sottotitolo applicazione
@@ -364,6 +368,18 @@ label_watched_issues: Watched issues
 label_related_issues: Related issues
 label_applied_status: Applied status
 label_loading: Loading...
+label_relation_new: New relation
+label_relation_delete: Delete relation
+label_relates_to: related tp
+label_duplicates: duplicates
+label_blocks: blocks
+label_blocked_by: blocked by
+label_precedes: precedes
+label_follows: follows
+label_end_to_start: start to end
+label_end_to_end: end to end
+label_start_to_start: start to start
+label_start_to_end: start to end
 
 button_login: Login
 button_submit: Invia
index 274171d6dfaa93a2820d1ee00f0a5192d8e3f7a0..f746faf970a93c194660d9bd0ac23be054b74195 100644 (file)
@@ -34,6 +34,8 @@ activerecord_error_taken: はすでに登録されています
 activerecord_error_not_a_number: が数字ではありません
 activerecord_error_not_a_date: の日付が間違っています
 activerecord_error_greater_than_start_date: を開始日より後にしてください
+activerecord_error_not_same_project: doesn't belong to the same project
+activerecord_error_circular_dependency: This relation would create a circular dependency
 
 general_fmt_age: %d歳
 general_fmt_age_plural: %d歳
@@ -150,6 +152,8 @@ field_activity: 活動
 field_spent_on: 日付
 field_identifier: 識別子
 field_is_filter: Used as a filter
+field_issue_to_id: Related issue
+field_delay: Delay
 
 setting_app_title: アプリケーションのタイトル
 setting_app_subtitle: アプリケーションのサブタイトル
@@ -365,6 +369,18 @@ label_watched_issues: Watched issues
 label_related_issues: Related issues
 label_applied_status: Applied status
 label_loading: Loading...
+label_relation_new: New relation
+label_relation_delete: Delete relation
+label_relates_to: related tp
+label_duplicates: duplicates
+label_blocks: blocks
+label_blocked_by: blocked by
+label_precedes: precedes
+label_follows: follows
+label_end_to_start: start to end
+label_end_to_end: end to end
+label_start_to_start: start to start
+label_start_to_end: start to end
 
 button_login: ログイン
 button_submit: 変更
index 4719e4174342f2e641a02adc17819da40d436ccf..0d8bfc67c3eda58e2bb27d309eb4819611bc9ada 100644 (file)
@@ -33,6 +33,8 @@ activerecord_error_taken: ja esta examinado
 activerecord_error_not_a_number: nao e um numero
 activerecord_error_not_a_date: nao e uma data valida
 activerecord_error_greater_than_start_date: deve ser maior que a data inicial
+activerecord_error_not_same_project: doesn't belong to the same project
+activerecord_error_circular_dependency: This relation would create a circular dependency
 
 general_fmt_age: %d yr
 general_fmt_age_plural: %d yrs
@@ -149,6 +151,8 @@ field_activity: Atividade
 field_spent_on: Data
 field_identifier: Identificador
 field_is_filter: Used as a filter
+field_issue_to_id: Related issue
+field_delay: Delay
 
 setting_app_title: Titulo da aplicacao
 setting_app_subtitle: Sub-titulo da aplicacao
@@ -364,6 +368,18 @@ label_watched_issues: Watched issues
 label_related_issues: Related issues
 label_applied_status: Applied status
 label_loading: Loading...
+label_relation_new: New relation
+label_relation_delete: Delete relation
+label_relates_to: related tp
+label_duplicates: duplicates
+label_blocks: blocks
+label_blocked_by: blocked by
+label_precedes: precedes
+label_follows: follows
+label_end_to_start: start to end
+label_end_to_end: end to end
+label_start_to_start: start to start
+label_start_to_end: start to end
 
 button_login: Login
 button_submit: Enviar
index 79f998c1c32ade21d103a2e6b14a37a63448fdd3..344d8152bcd538cd5612f3ecec343315fbdb9998 100644 (file)
@@ -36,6 +36,8 @@ activerecord_error_taken: has already been taken
 activerecord_error_not_a_number: 不是数字
 activerecord_error_not_a_date: 不是有效的日期
 activerecord_error_greater_than_start_date: 必需大于开始日期
+activerecord_error_not_same_project: doesn't belong to the same project
+activerecord_error_circular_dependency: This relation would create a circular dependency
 
 general_fmt_age: %d yr
 general_fmt_age_plural: %d yrs
@@ -152,6 +154,8 @@ field_activity: 活动
 field_spent_on: 日期
 field_identifier: Identifier
 field_is_filter: Used as a filter
+field_issue_to_id: Related issue
+field_delay: Delay
 
 setting_app_title: 应用程序标题
 setting_app_subtitle: 应用程序子标题
@@ -367,6 +371,18 @@ label_watched_issues: Watched issues
 label_related_issues: Related issues
 label_applied_status: Applied status
 label_loading: Loading...
+label_relation_new: New relation
+label_relation_delete: Delete relation
+label_relates_to: related tp
+label_duplicates: duplicates
+label_blocks: blocks
+label_blocked_by: blocked by
+label_precedes: precedes
+label_follows: follows
+label_end_to_start: start to end
+label_end_to_end: end to end
+label_start_to_start: start to start
+label_start_to_end: start to end
 
 button_login: 登录
 button_submit: 提交
index 81708d1d93904f6264f466cad3335f52b7f6923c..7ca0cc4d817954a235c09d8208a899b5e309cab3 100644 (file)
@@ -32,6 +32,15 @@ function showTab(name) {
        return false;
 }
 
+function setPredecessorFieldsVisibility() {
+    relationType = $('relation_relation_type');
+    if (relationType && relationType.value == "precedes") {
+        Element.show('predecessor_fields');
+    } else {
+        Element.hide('predecessor_fields');
+    }
+}
+
 /* shows and hides ajax indicator */
 Ajax.Responders.register({
     onCreate: function(){