OSDN Git Service

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 be1b8c0..99dc687 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 6d8c386..d3a7147 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 72a953f..6dc812c 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 2eb01f0..d7d9bcf 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 dfa2a5d..8e2670a 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 41b6c6d..6041f71 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 efd5e38..35e4328 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 7fcb2b1..fadcaad 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 806c8d4..e6c9002 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 8423ba9..394417a 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 0c48ee2..2deb091 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 274171d..f746faf 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 4719e41..0d8bfc6 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 79f998c..344d815 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 81708d1..7ca0cc4 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(){