Commit 92b02014 authored by Jean-Philippe Lang's avatar Jean-Philippe Lang

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
parent 987e843c
# 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
......@@ -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
......
......@@ -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
......
# 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
# 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
# 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
<%= 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();" %>
<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 %>
......@@ -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>
......
......@@ -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'
......
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
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
......@@ -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: Изпращане
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
_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
......
......@@ -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
......
......@@ -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: 変更
......
......@@ -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
......
......@@ -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: 提交
......
......@@ -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(){
......
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