summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2007-05-05 13:22:27 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2007-05-05 13:22:27 +0000
commit92b02014d21f0e60230fc7a5c3c5ad71dac6e472 (patch)
tree30fcce490ea2c6decb6ea34b589f11f04bfd381d
parent987e843cd195edc402c8b2c7c665534ddb02af45 (diff)
downloadredmine-92b02014d21f0e60230fc7a5c3c5ad71dac6e472.tar.gz
redmine-92b02014d21f0e60230fc7a5c3c5ad71dac6e472.zip
Issue relations first commit (not thoroughly tested). 4 kinds of relation are available:
* 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
-rw-r--r--app/controllers/issue_relations_controller.rb59
-rw-r--r--app/controllers/issues_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb3
-rw-r--r--app/helpers/issue_relations_helper.rb23
-rw-r--r--app/models/issue.rb49
-rw-r--r--app/models/issue_relation.rb79
-rw-r--r--app/views/issue_relations/_form.rhtml10
-rw-r--r--app/views/issues/_relations.rhtml22
-rw-r--r--app/views/issues/show.rhtml6
-rw-r--r--config/routes.rb2
-rw-r--r--db/migrate/042_create_issue_relations.rb14
-rw-r--r--db/migrate/043_add_relations_permissions.rb11
-rw-r--r--lang/bg.yml16
-rw-r--r--lang/de.yml16
-rw-r--r--lang/en.yml16
-rw-r--r--lang/es.yml16
-rw-r--r--lang/fr.yml18
-rw-r--r--lang/it.yml16
-rw-r--r--lang/ja.yml16
-rw-r--r--lang/pt.yml16
-rw-r--r--lang/zh.yml16
-rw-r--r--public/javascripts/application.js9
22 files changed, 419 insertions, 16 deletions
diff --git a/app/controllers/issue_relations_controller.rb b/app/controllers/issue_relations_controller.rb
new file mode 100644
index 000000000..cb0ad552a
--- /dev/null
+++ b/app/controllers/issue_relations_controller.rb
@@ -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
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb
index be1b8c003..99dc687f8 100644
--- a/app/controllers/issues_controller.rb
+++ b/app/controllers/issues_controller.rb
@@ -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
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 6d8c3863e..d3a71478b 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -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
index 000000000..377059d5f
--- /dev/null
+++ b/app/helpers/issue_relations_helper.rb
@@ -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
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 72a953f62..6dc812ce4 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -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
index 000000000..05ea52057
--- /dev/null
+++ b/app/models/issue_relation.rb
@@ -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
index 000000000..8b514dc1a
--- /dev/null
+++ b/app/views/issue_relations/_form.rhtml
@@ -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
index 000000000..f817d3851
--- /dev/null
+++ b/app/views/issues/_relations.rhtml
@@ -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 %>
diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml
index 2eb01f094..d7d9bcf6d 100644
--- a/app/views/issues/show.rhtml
+++ b/app/views/issues/show.rhtml
@@ -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>
diff --git a/config/routes.rb b/config/routes.rb
index dfa2a5df2..8e2670a99 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -15,6 +15,8 @@ ActionController::Routing::Routes.draw do |map|
map.connect 'help/:ctrl/:page', :controller => 'help'
#map.connect ':controller/:action/:id/:sort_key/:sort_order'
+ 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
index 000000000..802c12437
--- /dev/null
+++ b/db/migrate/042_create_issue_relations.rb
@@ -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
index 000000000..3f1da8f27
--- /dev/null
+++ b/db/migrate/043_add_relations_permissions.rb
@@ -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
diff --git a/lang/bg.yml b/lang/bg.yml
index 41b6c6d88..6041f71b3 100644
--- a/lang/bg.yml
+++ b/lang/bg.yml
@@ -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: Изпращане
diff --git a/lang/de.yml b/lang/de.yml
index efd5e38b6..35e4328cc 100644
--- a/lang/de.yml
+++ b/lang/de.yml
@@ -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
diff --git a/lang/en.yml b/lang/en.yml
index 7fcb2b14b..fadcaad3f 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -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
diff --git a/lang/es.yml b/lang/es.yml
index 806c8d462..e6c9002e7 100644
--- a/lang/es.yml
+++ b/lang/es.yml
@@ -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
diff --git a/lang/fr.yml b/lang/fr.yml
index 8423ba93b..394417ac9 100644
--- a/lang/fr.yml
+++ b/lang/fr.yml
@@ -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
diff --git a/lang/it.yml b/lang/it.yml
index 0c48ee20e..2deb09115 100644
--- a/lang/it.yml
+++ b/lang/it.yml
@@ -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
diff --git a/lang/ja.yml b/lang/ja.yml
index 274171d6d..f746faf97 100644
--- a/lang/ja.yml
+++ b/lang/ja.yml
@@ -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: 変更
diff --git a/lang/pt.yml b/lang/pt.yml
index 4719e4174..0d8bfc67c 100644
--- a/lang/pt.yml
+++ b/lang/pt.yml
@@ -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
diff --git a/lang/zh.yml b/lang/zh.yml
index 79f998c1c..344d8152b 100644
--- a/lang/zh.yml
+++ b/lang/zh.yml
@@ -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: 提交
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index 81708d1d9..7ca0cc4d8 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -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(){