subissues.diff
| b/app/controllers/issues_controller.rb | ||
|---|---|---|
| 18 | 18 |
class IssuesController < ApplicationController |
| 19 | 19 |
menu_item :new_issue, :only => :new |
| 20 | 20 |
|
| 21 |
before_filter :find_issue, :only => [:show, :edit, :reply, :destroy_attachment] |
|
| 21 |
before_filter :find_issue_and_project_id, :only => [ :show_children, :hide_children ] |
|
| 22 |
before_filter :find_issue, :only => [:show, :edit, :reply, :destroy_attachment, :update_subject ] |
|
| 22 | 23 |
before_filter :find_issues, :only => [:bulk_edit, :move, :destroy] |
| 23 |
before_filter :find_project, :only => [:new, :update_form, :preview, :gantt, :calendar] |
|
| 24 |
before_filter :authorize, :except => [:index, :changes, :preview, :update_form, :context_menu] |
|
| 24 |
before_filter :find_project, :only => [:new, :auto_complete_for_issue_parent, :add_subissue, :update_form, :preview, :gantt, :calendar]
|
|
| 25 |
before_filter :authorize, :except => [:index, :changes, :preview, :update_form, :context_menu, :show_children, :hide_children, :auto_complete_for_issue_parent ]
|
|
| 25 | 26 |
before_filter :find_optional_project, :only => [:index, :changes] |
| 26 | 27 |
accept_key_auth :index, :changes |
| 27 | 28 | |
| ... | ... | |
| 43 | 44 |
include SortHelper |
| 44 | 45 |
include IssuesHelper |
| 45 | 46 |
helper :timelog |
| 47 |
include ActionView::Helpers::PrototypeHelper |
|
| 48 | ||
| 49 |
def update_subject |
|
| 50 |
@notes = params[:notes] |
|
| 51 |
journal = @issue.init_journal(User.current, @notes) |
|
| 52 |
@edit_allowed = User.current.allowed_to?(:edit_issues, @project) |
|
| 53 |
# User can change issue attributes only if he has :edit permission or if a workflow transition is allowed |
|
| 54 |
if (@edit_allowed || !@allowed_statuses.empty?) && params[:subject] |
|
| 55 |
@issue.subject = params[:subject] |
|
| 56 |
end |
|
| 57 |
if @issue.save |
|
| 58 |
if !journal.new_record? |
|
| 59 |
# Only send notification if something was actually changed |
|
| 60 |
flash[:notice] = l(:notice_successful_update) |
|
| 61 |
Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
|
|
| 62 |
end |
|
| 63 |
render(:text => params[:subject]) |
|
| 64 |
end |
|
| 65 |
rescue ActiveRecord::StaleObjectError |
|
| 66 |
# Optimistic locking exception |
|
| 67 |
flash.now[:error] = l(:notice_locking_conflict) |
|
| 68 |
end |
|
| 69 |
|
|
| 70 |
def show_children |
|
| 71 |
retrieve_query |
|
| 72 |
if @query.valid? |
|
| 73 |
render :update do |page| |
|
| 74 |
page.replace "issue-#{@issue.id}", :partial => 'show_children', :locals => {:issue => @issue, :query => @query}
|
|
| 75 |
end |
|
| 76 |
end |
|
| 77 |
end |
|
| 78 |
|
|
| 79 |
def hide_children |
|
| 80 |
retrieve_query #verificar necessidade |
|
| 81 |
if @query.valid? |
|
| 82 |
render :update do |page| |
|
| 83 |
page.select(".issue-#{@issue.id}-child").each do |child|
|
|
| 84 |
child.remove |
|
| 85 |
end |
|
| 86 |
page.select("#issue-#{@issue.id} a.contract-link").each do |contractIcon|
|
|
| 87 |
contractIcon.replace link_to_remote(image_tag("expand.png", :class=>'expand-icon'), {:url => {:controller => 'issues', :action => "show_children", :id => @issue, :project_id => @project}}, :class=>'expand-link')
|
|
| 88 |
end |
|
| 89 |
end |
|
| 90 |
end |
|
| 91 |
end |
|
| 92 | ||
| 93 |
def auto_complete_for_issue_parent |
|
| 94 |
@phrase = params[:issue_parent] |
|
| 95 |
@candidates = [] |
|
| 96 | ||
| 97 |
# If cross project issue relations is allowed we should get |
|
| 98 |
# candidates from every project |
|
| 99 |
if Setting.cross_project_issue_relations? |
|
| 100 |
projects_to_search = nil |
|
| 101 |
else |
|
| 102 |
projects_to_search = [ @project ] + @project.active_children |
|
| 103 |
end |
|
| 104 | ||
| 105 |
# Try to find issue by id. |
|
| 106 |
if @phrase.match(/^#?(\d+)$/) |
|
| 107 |
if Setting.cross_project_issue_relations? |
|
| 108 |
issue = Issue.find_by_id( $1) |
|
| 109 |
else |
|
| 110 |
issue = Issue.find_by_id_and_project_id( $1, projects_to_search.collect { |i| i.id})
|
|
| 111 |
end |
|
| 112 |
@candidates = [ issue ] if issue |
|
| 113 |
end |
|
| 114 | ||
| 115 |
# If finding by id is fail, try to find by searching in subject |
|
| 116 |
# and description. |
|
| 117 |
if @candidates.empty? |
|
| 118 |
# extract tokens from the question |
|
| 119 |
# eg. hello "bye bye" => ["hello", "bye bye"] |
|
| 120 |
tokens = @phrase.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).collect {|m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '')}
|
|
| 121 |
# tokens must be at least 3 character long |
|
| 122 |
tokens = tokens.uniq.select {|w| w.length > 2 }
|
|
| 123 |
like_tokens = tokens.collect {|w| "%#{w.downcase}%"}
|
|
| 124 | ||
| 125 |
@candidates, count = Issue.search( like_tokens, projects_to_search, :before => true) |
|
| 126 |
end |
|
| 127 | ||
| 128 |
render :inline => "<%= auto_complete_result_parent_issue( @candidates, @phrase) %>" |
|
| 129 |
end |
|
| 46 | 130 | |
| 47 | 131 |
def index |
| 48 | 132 |
sort_init "#{Issue.table_name}.id", "desc"
|
| ... | ... | |
| 58 | 142 |
end |
| 59 | 143 |
@issue_count = Issue.count(:include => [:status, :project], :conditions => @query.statement) |
| 60 | 144 |
@issue_pages = Paginator.new self, @issue_count, limit, params['page'] |
| 61 |
@issues = Issue.find :all, :order => sort_clause, |
|
| 62 |
:include => [ :assigned_to, :status, :tracker, :project, :priority, :category, :fixed_version ], |
|
| 63 |
:conditions => @query.statement, |
|
| 64 |
:limit => limit, |
|
| 65 |
:offset => @issue_pages.current.offset |
|
| 145 |
@issues = Issue.find_with_parents( :all, :order => sort_clause, |
|
| 146 |
:include => [ :assigned_to, |
|
| 147 |
:status, |
|
| 148 |
:tracker, |
|
| 149 |
:project, |
|
| 150 |
:priority, |
|
| 151 |
:category, |
|
| 152 |
:fixed_version ], |
|
| 153 |
:conditions => @query.statement, |
|
| 154 |
:limit => limit, |
|
| 155 |
:offset => @issue_pages.current.offset) |
|
| 156 |
|
|
| 66 | 157 |
respond_to do |format| |
| 67 | 158 |
format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
|
| 68 | 159 |
format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
|
| ... | ... | |
| 132 | 223 |
end |
| 133 | 224 |
@issue.status = default_status |
| 134 | 225 |
@allowed_statuses = ([default_status] + default_status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)).uniq |
| 135 |
|
|
| 226 |
@parent_issue = Issue.find( params[:issue_parent_issue_id]) unless params[:issue_parent_issue_id].blank? |
|
| 227 | ||
| 136 | 228 |
if request.get? || request.xhr? |
| 137 | 229 |
@issue.start_date ||= Date.today |
| 138 | 230 |
else |
| ... | ... | |
| 140 | 232 |
# Check that the user is allowed to apply the requested status |
| 141 | 233 |
@issue.status = (@allowed_statuses.include? requested_status) ? requested_status : default_status |
| 142 | 234 |
if @issue.save |
| 235 |
set_parent( @issue, params[:issue_parent_issue_id]) if params[:issue_parent_issue_id] |
|
| 143 | 236 |
attach_files(@issue, params[:attachments]) |
| 144 | 237 |
flash[:notice] = l(:notice_successful_create) |
| 145 | 238 |
Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added')
|
| ... | ... | |
| 150 | 243 |
@priorities = Enumeration::get_values('IPRI')
|
| 151 | 244 |
render :layout => !request.xhr? |
| 152 | 245 |
end |
| 246 | ||
| 247 |
def add_subissue |
|
| 248 |
if params[:issue_parent_issue_id].nil? |
|
| 249 |
flash.now[:error] = 'No parent issue specified.' |
|
| 250 |
render :nothing => true, :layout => true |
|
| 251 |
return |
|
| 252 |
else |
|
| 253 |
redirect_to( :controller => 'issues', :action => 'new', |
|
| 254 |
:issue_parent_issue_id => params[:issue_parent_issue_id]) |
|
| 255 |
return |
|
| 256 |
end |
|
| 257 |
end |
|
| 153 | 258 |
|
| 154 | 259 |
# Attributes that can be updated on workflow transition (without :edit permission) |
| 155 | 260 |
# TODO: make it configurable (at least per role) |
| ... | ... | |
| 177 | 282 |
attachments = attach_files(@issue, params[:attachments]) |
| 178 | 283 |
attachments.each {|a| journal.details << JournalDetail.new(:property => 'attachment', :prop_key => a.id, :value => a.filename)}
|
| 179 | 284 |
if (@time_entry.hours.nil? || @time_entry.valid?) && @issue.save |
| 285 |
set_parent(@issue, params[:issue_parent_issue_id]) if params[:issue_parent_issue_id] |
|
| 180 | 286 |
# Log spend time |
| 181 | 287 |
if current_role.allowed_to?(:log_time) |
| 182 | 288 |
@time_entry.save |
| ... | ... | |
| 236 | 342 |
call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
|
| 237 | 343 |
# Don't save any change to the issue if the user is not authorized to apply the requested status |
| 238 | 344 |
if (status.nil? || (issue.status.new_status_allowed_to?(status, current_role, issue.tracker) && issue.status = status)) && issue.save |
| 345 |
set_parent(issue, params[:issue_parent_issue_id]) unless params[:issue_parent_issue_id].blank? |
|
| 239 | 346 |
# Send notification for each issue (if changed) |
| 240 | 347 |
Mailer.deliver_issue_edit(journal) if journal.details.any? && Setting.notified_events.include?('issue_updated')
|
| 241 | 348 |
else |
| ... | ... | |
| 410 | 517 | |
| 411 | 518 |
def update_form |
| 412 | 519 |
@issue = Issue.new(params[:issue]) |
| 520 |
@parent_issue = @issue.parent |
|
| 413 | 521 |
render :action => :new, :layout => false |
| 414 | 522 |
end |
| 415 | 523 |
|
| ... | ... | |
| 423 | 531 |
private |
| 424 | 532 |
def find_issue |
| 425 | 533 |
@issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) |
| 534 |
@parent_issue = @issue.parent |
|
| 426 | 535 |
@project = @issue.project |
| 427 | 536 |
rescue ActiveRecord::RecordNotFound |
| 428 | 537 |
render_404 |
| 429 | 538 |
end |
| 430 | 539 |
|
| 540 |
def find_issue_and_project_id |
|
| 541 |
@issue = Issue.find( params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) |
|
| 542 |
@parent_issue = @issue.parent |
|
| 543 |
@project = Project.find( params[:project_id]) |
|
| 544 |
rescue ActiveRecord::RecordNotFound |
|
| 545 |
render_404 |
|
| 546 |
end |
|
| 547 | ||
| 431 | 548 |
# Filter for bulk operations |
| 432 | 549 |
def find_issues |
| 433 | 550 |
@issues = Issue.find_all_by_id(params[:id] || params[:ids]) |
| b/app/controllers/projects_controller.rb | ||
|---|---|---|
| 42 | 42 |
helper :repositories |
| 43 | 43 |
include RepositoriesHelper |
| 44 | 44 |
include ProjectsHelper |
| 45 |
helper :versions |
|
| 46 |
include VersionsHelper |
|
| 45 | 47 |
|
| 46 | 48 |
# Lists visible projects |
| 47 | 49 |
def index |
| ... | ... | |
| 271 | 273 |
@selected_tracker_ids = selectable_trackers.collect {|t| t.id.to_s }
|
| 272 | 274 |
end |
| 273 | 275 |
end |
| 276 |
|
|
| 277 |
|
|
| 278 |
def sort_as_tree(issues) |
|
| 279 |
issues.sort!{|a,b| a.hierarchical_level <=> b.hierarchical_level}
|
|
| 280 |
@sorted_issues = [] |
|
| 281 |
issues.each do |issue| |
|
| 282 |
if @sorted_issues.empty? |
|
| 283 |
@sorted_issues << issue |
|
| 284 |
next |
|
| 285 |
end |
|
| 286 |
@time_to_stop = false #indicates when this task reaches its parent task (important because it has to stop between its parent task and the next aunt task |
|
| 287 |
@sorted_issues.each do |sorted_issue| |
|
| 288 |
#if same parent and smaller date, stop; if same parent, same date and smaller id, stop; after parent and before next parent, stop; |
|
| 289 |
if ((sorted_issue.parent == issue.parent) && (sorted_issue.start_date > issue.start_date)) || |
|
| 290 |
((sorted_issue.parent == issue.parent) && (sorted_issue.start_date == issue.start_date) && (sorted_issue.id > issue.id)) || |
|
| 291 |
(@time_to_stop && (sorted_issue.hierarchical_level < issue.hierarchical_level)) |
|
| 292 |
@sorted_issues.insert(@sorted_issues.index(sorted_issue), issue) |
|
| 293 |
break |
|
| 294 |
end |
|
| 295 |
@time_to_stop = true if sorted_issue == issue.parent |
|
| 296 |
end |
|
| 297 |
#if this issue's parent is the last element |
|
| 298 |
@sorted_issues << issue if @time_to_stop |
|
| 299 |
end |
|
| 300 |
@sorted_issues |
|
| 301 |
end |
|
| 302 |
|
|
| 303 |
#assumes that first level issues are ordered by date (sort_as_tree) |
|
| 304 |
def integrate_versions_with_issues_tree(issues, versions) |
|
| 305 |
versions.sort! {|x,y| x.start_date <=> y.start_date }
|
|
| 306 |
versions.each do |version| |
|
| 307 |
issues << version if issues.empty? |
|
| 308 |
issues.each do |issue| |
|
| 309 |
if ((issue.is_a? Issue && issue.root?) || (issue.is_a? Version)) && version.start_date < issue.start_date |
|
| 310 |
#insert version before a root task or another version whose date is immediately after this task's one |
|
| 311 |
issues.insert(issues.index(issue), version) |
|
| 312 |
elsif issue == issues.last |
|
| 313 |
issues << version |
|
| 314 |
end |
|
| 315 |
end |
|
| 316 |
end |
|
| 317 |
issues |
|
| 318 |
end |
|
| 319 |
|
|
| 274 | 320 |
end |
| b/app/controllers/versions_controller.rb | ||
|---|---|---|
| 20 | 20 |
before_filter :find_project, :authorize |
| 21 | 21 | |
| 22 | 22 |
def show |
| 23 |
@issues = @version.fixed_issues.find(:all, |
|
| 24 |
:include => [:status, :tracker], |
|
| 25 |
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id")
|
|
| 26 |
@issues = Issue.find_with_parents( @issues.collect { |i| i.id})
|
|
| 23 | 27 |
end |
| 24 | 28 |
|
| 25 | 29 |
def edit |
| b/app/helpers/issues_helper.rb | ||
|---|---|---|
| 19 | 19 | |
| 20 | 20 |
module IssuesHelper |
| 21 | 21 |
include ApplicationHelper |
| 22 |
|
|
| 23 |
def issue_ancestors(issue=@issue) |
|
| 24 |
ancestors = "" |
|
| 25 |
return "" if issue.parent == nil |
|
| 26 |
ancestors += "issue-#{issue.parent.id}-child " + issue_ancestors(issue.parent)
|
|
| 27 |
end |
|
| 22 | 28 | |
| 23 | 29 |
def render_issue_tooltip(issue) |
| 24 | 30 |
@cached_label_start_date ||= l(:field_start_date) |
| ... | ... | |
| 185 | 191 |
export.rewind |
| 186 | 192 |
export |
| 187 | 193 |
end |
| 194 |
|
|
| 195 |
def set_parent(issue, parent_id) |
|
| 196 |
if (issue && parent_id.to_s.size > 0) |
|
| 197 |
issue.relations_from.each do |relation| |
|
| 198 |
if relation.relation_type == IssueRelation::TYPE_PARENTS |
|
| 199 |
relation.destroy |
|
| 200 |
end |
|
| 201 |
end |
|
| 202 |
issue.reload |
|
| 203 |
IssueRelation.create do |relation| |
|
| 204 |
relation.issue_from = issue |
|
| 205 |
relation.issue_to = Issue.find(parent_id) |
|
| 206 |
relation.relation_type = IssueRelation::TYPE_PARENTS |
|
| 207 |
unless relation.save |
|
| 208 |
flash[:error] = "Can't set ##{parent_id} as parent for the issue."
|
|
| 209 |
end |
|
| 210 |
end unless parent_id == '0' |
|
| 211 |
end |
|
| 212 |
end |
|
| 213 |
|
|
| 214 |
def auto_complete_result_parent_issue(candidates, phrase) |
|
| 215 |
return "" if candidates.empty? |
|
| 216 |
candidates.map! do |c| |
|
| 217 |
content_tag("li", highlight( c.to_s, phrase), :id => String( c[:id]))
|
|
| 218 |
end |
|
| 219 |
content_tag("ul", candidates.uniq)
|
|
| 220 |
end |
|
| 188 | 221 |
end |
| b/app/helpers/queries_helper.rb | ||
|---|---|---|
| 1 |
# -*- coding: mule-utf-8 -*- |
|
| 1 | 2 |
# redMine - project management software |
| 2 | 3 |
# Copyright (C) 2006-2007 Jean-Philippe Lang |
| 3 | 4 |
# |
| ... | ... | |
| 40 | 41 |
else |
| 41 | 42 |
case column.name |
| 42 | 43 |
when :subject |
| 43 |
h((@project.nil? || @project != issue.project) ? "#{issue.project.name} - " : '') +
|
|
| 44 |
link_to(h(value), :controller => 'issues', :action => 'show', :id => issue) |
|
| 44 |
subject_in_tree(issue, value) |
|
| 45 | 45 |
when :done_ratio |
| 46 | 46 |
progress_bar(value, :width => '80px') |
| 47 | 47 |
when :fixed_version |
| ... | ... | |
| 52 | 52 |
end |
| 53 | 53 |
end |
| 54 | 54 |
end |
| 55 |
|
|
| 56 |
def subject_in_tree(issue, value) |
|
| 57 |
image = "" |
|
| 58 |
unless issue.edge? #don't show + or - icons for leaf issues |
|
| 59 |
#o controle das tarefas a ser mostradas não está sendo feito por _list? verificar |
|
| 60 |
image = @show_all_issues || |
|
| 61 |
@show_children ? |
|
| 62 |
link_to_remote(image_tag("contract.png", :class=>'contract-icon'), {:url => {:controller => 'issues', :action => "hide_children", :id => issue, :project_id => @project}}, :class=>'contract-link') :
|
|
| 63 |
link_to_remote(image_tag("expand.png", :class=>'expand-icon'), {:url => {:controller => 'issues', :action => "show_children", :id => issue, :project_id => @project}}, :class=>'expand-link')
|
|
| 64 |
end |
|
| 65 |
content_tag('span', image + content_tag('div', subject_text(issue, value), :class=>'issue-subject'), :class=>"issue-subject-level-#{issue.hierarchical_level}")
|
|
| 66 |
end |
|
| 67 |
|
|
| 68 |
def subject_text(issue, value) |
|
| 69 |
subject_text = link_to(h(value), :controller => 'issues', :action => 'show', :id => issue) |
|
| 70 |
h((@project.nil? || @project != issue.project) ? "#{issue.project.name} - " : '') + subject_text
|
|
| 71 |
end |
|
| 72 |
|
|
| 55 | 73 |
end |
| b/app/helpers/versions_helper.rb | ||
|---|---|---|
| 44 | 44 |
def status_by_options_for_select(value) |
| 45 | 45 |
options_for_select(STATUS_BY_CRITERIAS.collect {|criteria| [l("field_#{criteria}".to_sym), criteria]}, value)
|
| 46 | 46 |
end |
| 47 | ||
| 48 |
def render_list_of_related_issues( issues, version, current_level = 1) |
|
| 49 |
issues_on_current_level = issues.select { |i| i.hierarchical_level == current_level }
|
|
| 50 |
issues -= issues_on_current_level |
|
| 51 |
content_tag( 'ul') do |
|
| 52 |
html = '' |
|
| 53 |
issues_on_current_level.each do |issue| |
|
| 54 |
opts_for_issue_li = { }
|
|
| 55 |
if !issue.fixed_version or issue.fixed_version != version |
|
| 56 |
opts_for_issue_li[:style] = 'opacity: 0.5;filter: alpha(opacity=50);' |
|
| 57 |
end |
|
| 58 |
html << content_tag( 'li', opts_for_issue_li) do |
|
| 59 |
opts = { }
|
|
| 60 |
if issue.done_ratio == 100 |
|
| 61 |
opts[:style] = 'font-weight: bold' |
|
| 62 |
end |
|
| 63 |
link_to_issue(issue, opts) + ": " + h(issue.subject) |
|
| 64 |
end |
|
| 65 |
children_to_print = issues & issue.children |
|
| 66 |
children_to_print += issues.select { |i| i.hierarchical_level >= current_level + 2}
|
|
| 67 |
unless children_to_print.empty? |
|
| 68 |
html << render_list_of_related_issues( children_to_print, version, current_level + 1) |
|
| 69 |
end |
|
| 70 |
end |
|
| 71 |
html |
|
| 72 |
end |
|
| 73 |
end |
|
| 47 | 74 |
end |
| b/app/models/issue.rb | ||
|---|---|---|
| 18 | 18 |
class Issue < ActiveRecord::Base |
| 19 | 19 |
belongs_to :project |
| 20 | 20 |
belongs_to :tracker |
| 21 |
belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
|
|
| 22 |
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
|
|
| 23 |
belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
|
|
| 24 |
belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id' |
|
| 25 |
belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id'
|
|
| 26 |
belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' |
|
| 21 |
belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
|
|
| 22 |
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
|
|
| 23 |
belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
|
|
| 24 |
belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
|
|
| 25 |
belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id'
|
|
| 26 |
belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
|
|
| 27 | 27 | |
| 28 |
has_many :journals, :as => :journalized, :dependent => :destroy |
|
| 29 |
has_many :attachments, :as => :container, :dependent => :destroy |
|
| 28 |
has_many :journals, :as => :journalized, :dependent => :destroy
|
|
| 29 |
has_many :attachments, :as => :container, :dependent => :destroy
|
|
| 30 | 30 |
has_many :time_entries, :dependent => :delete_all |
| 31 | 31 |
has_and_belongs_to_many :changesets, :order => "#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC"
|
| 32 | 32 |
|
| 33 | 33 |
has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all |
| 34 |
has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
|
|
| 34 |
has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
|
|
| 35 | 35 |
|
| 36 | 36 |
acts_as_customizable |
| 37 | 37 |
acts_as_watchable |
| ... | ... | |
| 44 | 44 |
|
| 45 | 45 |
acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]}
|
| 46 | 46 |
|
| 47 |
validates_presence_of :subject, :description, :priority, :project, :tracker, :author, :status
|
|
| 48 |
validates_length_of :subject, :maximum => 255
|
|
| 49 |
validates_inclusion_of :done_ratio, :in => 0..100 |
|
| 47 |
validates_presence_of :subject, :description, :priority, :project, :tracker, :author, :status
|
|
| 48 |
validates_length_of :subject, :maximum => 255
|
|
| 49 |
validates_inclusion_of :done_ratio, :in => 0..100
|
|
| 50 | 50 |
validates_numericality_of :estimated_hours, :allow_nil => true |
| 51 | 51 | |
| 52 | 52 |
def after_initialize |
| ... | ... | |
| 99 | 99 |
return true |
| 100 | 100 |
end |
| 101 | 101 |
|
| 102 |
def priority_id=(pid) |
|
| 103 |
self.priority = nil |
|
| 104 |
write_attribute(:priority_id, pid) |
|
| 105 |
end |
|
| 106 |
|
|
| 107 | 102 |
def estimated_hours=(h) |
| 108 | 103 |
write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h) |
| 109 | 104 |
end |
| ... | ... | |
| 120 | 115 |
if start_date && soonest_start && start_date < soonest_start |
| 121 | 116 |
errors.add :start_date, :activerecord_error_invalid |
| 122 | 117 |
end |
| 118 | ||
| 119 |
if IssueStatus.find_by_id( @attributes['status_id']).is_closed? && children.find { |i| !i.closed? }
|
|
| 120 |
errors.add :status, "Can't close parent issue while on of the children still is open." |
|
| 121 |
end |
|
| 122 | ||
| 123 |
unless children.empty? |
|
| 124 |
children_max_fixed_version = children.select { |i| i.fixed_version } .max { |a,b| a.fixed_version <=> b.fixed_version }
|
|
| 125 |
if @attributes['fixed_version_id'] && children_max_fixed_version |
|
| 126 |
if Version.find_by_id( @attributes['fixed_version_id']) < children_max_fixed_version.fixed_version |
|
| 127 |
errors.add :fixed_version, "Can't set target version of parent issue lower than any of the children." |
|
| 128 |
end |
|
| 129 |
end |
|
| 130 |
end |
|
| 123 | 131 |
end |
| 124 | 132 |
|
| 125 | 133 |
def validate_on_create |
| ... | ... | |
| 140 | 148 |
@current_journal.details << JournalDetail.new(:property => 'attr', |
| 141 | 149 |
:prop_key => c, |
| 142 | 150 |
:old_value => @issue_before_change.send(c), |
| 143 |
:value => send(c)) unless send(c)==@issue_before_change.send(c) |
|
| 151 |
:value => send(c)) unless send(c)==@issue_before_change.send(c) || (!self.edge? && %w(status_id priority_id fixed_version_id start_date due_date done_ratio estimated_hours).include?(c))
|
|
| 144 | 152 |
} |
| 145 | 153 |
# custom fields changes |
| 146 | 154 |
custom_values.each {|c|
|
| ... | ... | |
| 153 | 161 |
} |
| 154 | 162 |
@current_journal.save |
| 155 | 163 |
end |
| 164 | ||
| 156 | 165 |
# Save the issue even if the journal is not saved (because empty) |
| 157 | 166 |
true |
| 158 | 167 |
end |
| ... | ... | |
| 164 | 173 |
# Update start/due dates of following issues |
| 165 | 174 |
relations_from.each(&:set_issue_to_dates) |
| 166 | 175 |
|
| 176 |
# Set default status of parent if new status openes the issue. |
|
| 177 |
relations_from.each do |relation| |
|
| 178 |
if relation.relation_type == IssueRelation::TYPE_PARENTS |
|
| 179 |
relation.set_issue_to_default_status |
|
| 180 |
relation.set_issue_to_target_version |
|
| 181 |
end |
|
| 182 |
end |
|
| 183 | ||
| 167 | 184 |
# Close duplicates if the issue was closed |
| 168 | 185 |
if @issue_before_change && !@issue_before_change.closed? && self.closed? |
| 169 | 186 |
duplicates.each do |duplicate| |
| ... | ... | |
| 177 | 194 |
end |
| 178 | 195 |
end |
| 179 | 196 |
end |
| 180 |
|
|
| 197 | ||
| 181 | 198 |
def init_journal(user, notes = "") |
| 182 | 199 |
@current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes) |
| 183 | 200 |
@issue_before_change = self.clone |
| ... | ... | |
| 189 | 206 |
@current_journal |
| 190 | 207 |
end |
| 191 | 208 |
|
| 209 |
def priority_id=(pid) |
|
| 210 |
self.priority = nil |
|
| 211 |
write_attribute(:priority_id, pid) |
|
| 212 |
end |
|
| 213 | ||
| 192 | 214 |
# Return true if the issue is closed, otherwise false |
| 193 | 215 |
def closed? |
| 194 | 216 |
self.status.is_closed? |
| ... | ... | |
| 240 | 262 |
# Returns the due date or the target due date if any |
| 241 | 263 |
# Used on gantt chart |
| 242 | 264 |
def due_before |
| 243 |
due_date || (fixed_version ? fixed_version.effective_date : nil) |
|
| 265 |
due_date || (fixed_version ? fixed_version.effective_date : 0) |
|
| 266 |
end |
|
| 267 |
|
|
| 268 |
def duration1 |
|
| 269 |
(start_date && due_date) ? (due_date - start_date + 1) : 0 |
|
| 244 | 270 |
end |
| 245 | 271 |
|
| 246 | 272 |
def duration |
| ... | ... | |
| 257 | 283 |
end |
| 258 | 284 |
end |
| 259 | 285 |
|
| 286 |
def done_ratio |
|
| 287 |
if children? |
|
| 288 |
@total_planned_days ||= 0 |
|
| 289 |
@total_actual_days ||= 0 |
|
| 290 |
children.each do |child| # from every subtask get the total number of days and the number of days already "worked" |
|
| 291 |
planned_days = child.duration1 |
|
| 292 |
actual_days = child.done_ratio ? (planned_days * child.done_ratio / 100).floor : 0 |
|
| 293 |
@total_planned_days += planned_days |
|
| 294 |
@total_actual_days += actual_days |
|
| 295 |
end |
|
| 296 |
@total_done_ratio = @total_planned_days != 0 ? (@total_actual_days * 100 / @total_planned_days).floor : 0 |
|
| 297 |
else |
|
| 298 |
read_attribute(:done_ratio) |
|
| 299 |
end |
|
| 300 |
end |
|
| 301 |
|
|
| 302 |
def estimated_hours |
|
| 303 |
if children? |
|
| 304 |
is_set = false |
|
| 305 |
children.each do |child| |
|
| 306 |
if child.estimated_hours |
|
| 307 |
if is_set |
|
| 308 |
@est_hours += child.estimated_hours |
|
| 309 |
else |
|
| 310 |
@est_hours = child.estimated_hours |
|
| 311 |
is_set = true |
|
| 312 |
end |
|
| 313 |
end |
|
| 314 |
end |
|
| 315 |
@est_hours |
|
| 316 |
else |
|
| 317 |
read_attribute(:estimated_hours) |
|
| 318 |
end |
|
| 319 |
end |
|
| 320 |
|
|
| 321 |
def start_date |
|
| 322 |
calculate 'start_date' |
|
| 323 |
end |
|
| 324 |
|
|
| 325 |
def due_date |
|
| 326 |
calculate 'due_date' |
|
| 327 |
end |
|
| 328 |
|
|
| 329 |
def calculate(field) |
|
| 330 |
if children? |
|
| 331 |
@value = eval "children.first.#{field}"
|
|
| 332 |
children.each do |child| |
|
| 333 |
case field |
|
| 334 |
when 'start_date' |
|
| 335 |
if child.start_date && (!@value || @value > child.start_date) |
|
| 336 |
@value = child.start_date |
|
| 337 |
end |
|
| 338 |
when 'due_date' |
|
| 339 |
if child.due_date && (!@value || @value < child.due_date) |
|
| 340 |
@value = child.due_date |
|
| 341 |
end |
|
| 342 |
end |
|
| 343 |
end |
|
| 344 |
@value |
|
| 345 |
else |
|
| 346 |
read_attribute(eval(":#{field}"))
|
|
| 347 |
end |
|
| 348 |
end |
|
| 349 | ||
| 350 |
def children? |
|
| 351 |
children != [] |
|
| 352 |
end |
|
| 353 |
|
|
| 354 |
def children |
|
| 355 |
children = [] |
|
| 356 |
relations_to.each do |relation| |
|
| 357 |
if relation.relation_type == IssueRelation::TYPE_PARENTS |
|
| 358 |
children << relation.other_issue(self) |
|
| 359 |
end |
|
| 360 |
end |
|
| 361 |
children |
|
| 362 |
end |
|
| 363 |
|
|
| 364 |
def parent |
|
| 365 |
relations_from.each do |relation| |
|
| 366 |
if relation.relation_type == IssueRelation::TYPE_PARENTS |
|
| 367 |
return parent = relation.other_issue(self) |
|
| 368 |
end |
|
| 369 |
end |
|
| 370 |
return nil |
|
| 371 |
end |
|
| 372 | ||
| 373 |
def parent? |
|
| 374 |
parent != nil |
|
| 375 |
end |
|
| 376 |
|
|
| 377 |
def root? |
|
| 378 |
!parent? |
|
| 379 |
end |
|
| 380 |
|
|
| 381 |
def ancestors(issue=self) |
|
| 382 |
a = [] |
|
| 383 |
return a if ! issue.parent? |
|
| 384 |
(a << issue.parent) | ancestors(issue.parent) |
|
| 385 |
end |
|
| 386 |
|
|
| 387 |
#First level tasks have hierarchical level = 1 and so on |
|
| 388 |
def hierarchical_level(issue=self) |
|
| 389 |
issue.parent? ? (1 + hierarchical_level(issue.parent)) : 1 |
|
| 390 |
end |
|
| 391 |
|
|
| 392 |
def edge? |
|
| 393 |
relations_to.each do |relation| |
|
| 394 |
if relation.relation_type == IssueRelation::TYPE_PARENTS |
|
| 395 |
return false |
|
| 396 |
end |
|
| 397 |
end |
|
| 398 |
return true |
|
| 399 |
end |
|
| 400 | ||
| 401 |
def orphan? |
|
| 402 |
root? && edge? |
|
| 403 |
end |
|
| 404 |
|
|
| 405 |
def self.find_with_parents( *args) |
|
| 406 |
issues = find( *args) |
|
| 407 |
return [] if issues.empty? |
|
| 408 |
issues.each do |i| |
|
| 409 |
while not i.root? |
|
| 410 |
issues += [ i.parent ] |
|
| 411 |
i = i.parent |
|
| 412 |
end |
|
| 413 |
end |
|
| 414 |
issues.uniq |
|
| 415 |
end |
|
| 416 |
|
|
| 260 | 417 |
def to_s |
| 261 | 418 |
"#{tracker} ##{id}: #{subject}"
|
| 262 | 419 |
end |
| b/app/models/issue_relation.rb | ||
|---|---|---|
| 17 | 17 | |
| 18 | 18 |
class IssueRelation < ActiveRecord::Base |
| 19 | 19 |
belongs_to :issue_from, :class_name => 'Issue', :foreign_key => 'issue_from_id' |
| 20 |
belongs_to :issue_to, :class_name => 'Issue', :foreign_key => 'issue_to_id' |
|
| 20 |
belongs_to :issue_to, :class_name => 'Issue', :foreign_key => 'issue_to_id'
|
|
| 21 | 21 |
|
| 22 | 22 |
TYPE_RELATES = "relates" |
| 23 | 23 |
TYPE_DUPLICATES = "duplicates" |
| 24 | 24 |
TYPE_BLOCKS = "blocks" |
| 25 | 25 |
TYPE_PRECEDES = "precedes" |
| 26 |
TYPE_PARENTS = "parents" |
|
| 26 | 27 |
|
| 27 |
TYPES = { TYPE_RELATES => { :name => :label_relates_to, :sym_name => :label_relates_to, :order => 1 },
|
|
| 28 |
TYPE_DUPLICATES => { :name => :label_duplicates, :sym_name => :label_duplicated_by, :order => 2 },
|
|
| 29 |
TYPE_BLOCKS => { :name => :label_blocks, :sym_name => :label_blocked_by, :order => 3 },
|
|
| 30 |
TYPE_PRECEDES => { :name => :label_precedes, :sym_name => :label_follows, :order => 4 },
|
|
| 28 |
TYPES = { TYPE_RELATES => { :name => :label_relates_to, :sym_name => :label_relates_to, :order => 1 },
|
|
| 29 |
TYPE_DUPLICATES => { :name => :label_duplicates, :sym_name => :label_duplicated_by, :order => 2 },
|
|
| 30 |
TYPE_BLOCKS => { :name => :label_blocks, :sym_name => :label_blocked_by, :order => 3 },
|
|
| 31 |
TYPE_PRECEDES => { :name => :label_precedes, :sym_name => :label_follows, :order => 4 },
|
|
| 32 |
TYPE_PARENTS => { :name => :label_parents, :sym_name => :label_children, :order => 5 },
|
|
| 31 | 33 |
}.freeze |
| 32 | 34 |
|
| 33 |
validates_presence_of :issue_from, :issue_to, :relation_type |
|
| 34 |
validates_inclusion_of :relation_type, :in => TYPES.keys |
|
| 35 |
validates_numericality_of :delay, :allow_nil => true |
|
| 36 |
validates_uniqueness_of :issue_to_id, :scope => :issue_from_id |
|
| 35 |
validates_presence_of :issue_from, :issue_to, :relation_type |
|
| 36 |
validates_inclusion_of :relation_type, :in => TYPES.keys |
|
| 37 |
validates_uniqueness_of :relation_type, :scope => [:issue_from_id, :relation_type], :message=>l(:error_issue_can_have_only_one_parent) |
|
| 38 |
validates_numericality_of :delay, :allow_nil => true |
|
| 39 |
validates_uniqueness_of :issue_to_id, :scope => :issue_from_id |
|
| 37 | 40 |
|
| 38 | 41 |
def validate |
| 39 | 42 |
if issue_from && issue_to |
| ... | ... | |
| 57 | 60 |
else |
| 58 | 61 |
self.delay = nil |
| 59 | 62 |
end |
| 63 | ||
| 64 |
# Set new status to parent if new status openes the issue. |
|
| 65 |
if TYPE_PARENTS == relation_type |
|
| 66 |
set_issue_to_default_status |
|
| 67 |
set_issue_to_target_version |
|
| 68 |
end |
|
| 69 | ||
| 60 | 70 |
set_issue_to_dates |
| 61 | 71 |
end |
| 72 | ||
| 73 |
def set_issue_to_default_status |
|
| 74 |
if issue_to.closed? && !issue_from.closed? |
|
| 75 |
issue_to.update_attribute :status, IssueStatus.default |
|
| 76 |
end |
|
| 77 |
end |
|
| 78 | ||
| 79 |
def set_issue_to_target_version |
|
| 80 |
if issue_to.fixed_version.nil? && issue_from.fixed_version or |
|
| 81 |
( issue_to.fixed_version && issue_from.fixed_version and |
|
| 82 |
issue_to.fixed_version.project == issue_from.fixed_version.project and |
|
| 83 |
issue_to.fixed_version < issue_from.fixed_version ) |
|
| 84 |
issue_to.update_attribute :fixed_version, issue_from.fixed_version |
|
| 85 |
end |
|
| 86 |
end |
|
| 62 | 87 |
|
| 63 | 88 |
def set_issue_to_dates |
| 64 | 89 |
soonest_start = self.successor_soonest_start |
| b/app/models/version.rb | ||
|---|---|---|
| 26 | 26 |
validates_length_of :name, :maximum => 60 |
| 27 | 27 |
validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => 'activerecord_error_not_a_date', :allow_nil => true
|
| 28 | 28 |
|
| 29 |
include Comparable |
|
| 30 |
|
|
| 29 | 31 |
def start_date |
| 30 | 32 |
effective_date |
| 31 | 33 |
end |
| b/app/views/issues/_edit.rhtml | ||
|---|---|---|
| 15 | 15 |
<%= render :partial => (@edit_allowed ? 'form' : 'form_update'), :locals => {:f => f} %>
|
| 16 | 16 |
</fieldset> |
| 17 | 17 |
<% end %> |
| 18 |
<% if authorize_for('timelog', 'edit') %>
|
|
| 18 |
<% if authorize_for('timelog', 'edit') && @issue.edge? %>
|
|
| 19 | 19 |
<fieldset class="tabular"><legend><%= l(:button_log_time) %></legend> |
| 20 | 20 |
<% fields_for :time_entry, @time_entry, { :builder => TabularFormBuilder, :lang => current_language} do |time_entry| %>
|
| 21 | 21 |
<div class="splitcontentleft"> |
| b/app/views/issues/_form.rhtml | ||
|---|---|---|
| 1 |
<!-- This function is needed for get ID from the text field with parent issue selection. --> |
|
| 2 |
<script type="text/javascript"> |
|
| 3 |
//<![CDATA[ |
|
| 4 |
function setParentIssueValue(element, value) {
|
|
| 5 |
document.getElementById('issue_parent_issue_id').value = value.id;
|
|
| 6 |
} |
|
| 7 |
//]]> |
|
| 8 |
</script> |
|
| 1 | 9 |
<% if @issue.new_record? %> |
| 2 | 10 |
<p><%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %></p>
|
| 3 | 11 |
<%= observe_field :issue_tracker_id, :url => { :action => :new },
|
| ... | ... | |
| 16 | 24 |
</div> |
| 17 | 25 | |
| 18 | 26 |
<div class="splitcontentleft"> |
| 19 |
<% if @issue.new_record? || @allowed_statuses.any? %>
|
|
| 27 |
<% if (@issue.new_record? || @allowed_statuses.any?) %>
|
|
| 20 | 28 |
<p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %></p>
|
| 21 | 29 |
<% else %> |
| 22 | 30 |
<p><label><%= l(:field_status) %></label> <%= @issue.status.name %></p> |
| 23 | 31 |
<% end %> |
| 24 | 32 | |
| 25 | 33 |
<p><%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), :required => true %></p>
|
| 34 | ||
| 26 | 35 |
<p><%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %></p>
|
| 27 | 36 |
<p><%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
|
| 28 | 37 |
<%= prompt_to_remote(l(:label_issue_category_new), |
| ... | ... | |
| 35 | 44 |
</div> |
| 36 | 45 | |
| 37 | 46 |
<div class="splitcontentright"> |
| 47 |
<% if @issue.edge? %> |
|
| 38 | 48 |
<p><%= f.text_field :start_date, :size => 10 %><%= calendar_for('issue_start_date') %></p>
|
| 39 | 49 |
<p><%= f.text_field :due_date, :size => 10 %><%= calendar_for('issue_due_date') %></p>
|
| 40 | 50 |
<p><%= f.text_field :estimated_hours, :size => 3 %> <%= l(:field_hours) %></p> |
| 41 | 51 |
<p><%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></p>
|
| 52 |
<% else %> |
|
| 53 |
<p><label><%= l(:field_start_date) %></label> <%= format_date(@issue.start_date) %></p> |
|
| 54 |
<p><label><%= l(:field_due_date) %></label> <%= format_date(@issue.due_date) %></p> |
|
| 55 |
<p><label><%= l(:field_done_ratio) %></label> <%= "#{@issue.done_ratio}%" %></p>
|
|
| 56 |
<% end %> |
|
| 57 |
<%= content_tag( :input, {},
|
|
| 58 |
:id => :issue_parent_issue_id, |
|
| 59 |
:type => :hidden, |
|
| 60 |
:name => 'issue_parent_issue_id', :value => @parent_issue ? @parent_issue.id : "") %> |
|
| 61 |
<p><label><%= l(:field_parent_issue) %></label> |
|
| 62 |
<% if authorize_for( 'issues', 'add_subissue') %> |
|
| 63 |
<%= text_field_with_auto_complete( :issue, :parent, |
|
| 64 |
{ :name => 'issue_parent', :value => @parent_issue || "" },
|
|
| 65 |
:url => { :action => 'auto_complete_for_issue_parent', :project_id => @project},
|
|
| 66 |
:after_update_element => 'setParentIssueValue') %> |
|
| 67 |
<% else %> |
|
| 68 |
<%= @parent_issue || "-" %> |
|
| 69 |
<% end %> |
|
| 70 |
</p> |
|
| 42 | 71 |
</div> |
| 43 | 72 | |
| 44 | 73 |
<div style="clear:both;"> </div> |
| b/app/views/issues/_form_update.rhtml | ||
|---|---|---|
| 3 | 3 |
<p><%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %></p>
|
| 4 | 4 |
</div> |
| 5 | 5 |
<div class="splitcontentright"> |
| 6 |
<% if @issue.edge? %> |
|
| 6 | 7 |
<p><%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></p>
|
| 8 |
<% else %> |
|
| 9 |
<p><label><%= l(:field_done_ratio) %></label> <%= "#{@issue.done_ratio}%" %></p>
|
|
| 10 |
<% end %> |
|
| 7 | 11 |
<%= content_tag('p', f.select(:fixed_version_id,
|
| 8 | 12 |
(@project.versions.sort.collect {|v| [v.name, v.id]}),
|
| 9 | 13 |
{ :include_blank => true })) unless @project.versions.empty? %>
|
| b/app/views/issues/_list.rhtml | ||
|---|---|---|
| 10 | 10 |
<% end %> |
| 11 | 11 |
</tr></thead> |
| 12 | 12 |
<tbody> |
| 13 |
<% issues.each do |issue| -%> |
|
| 13 |
<% issues.each do |issue| |
|
| 14 |
next if !@show_all_issues && (issue.hierarchical_level != 1) -%> |
|
| 14 | 15 |
<tr id="issue-<%= issue.id %>" class="issue hascontextmenu <%= cycle('odd', 'even') %> <%= "status-#{issue.status.position} priority-#{issue.priority.position}" %>">
|
| 15 | 16 |
<td class="checkbox"><%= check_box_tag("ids[]", issue.id, false, :id => nil) %></td>
|
| 16 | 17 |
<td><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %></td> |
| b/app/views/issues/_show_children.rhtml | ||
|---|---|---|
| 1 |
<% |
|
| 2 |
issues = [@issue] |
|
| 3 |
issues += @issue.children |
|
| 4 |
issues.each do |issue| |
|
| 5 |
is_parent = (issue == @issue) |
|
| 6 |
#used in queries_helper.rb when deciding which icon will be shown (if + or -) |
|
| 7 |
@show_children = is_parent -%> |
|
| 8 |
<tr id="issue-<%=issue.id%>" class="issue <%= issue_ancestors(issue) %> hascontextmenu <%= cycle('odd', 'even') %> <%= "status-#{issue.status.position} priority-#{issue.priority.position}" %>">
|
|
| 9 |
<td class="checkbox"><%= check_box_tag("ids[]", issue.id, false, :id => nil) %></td>
|
|
| 10 |
<td><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %></td> |
|
| 11 |
<% query.columns.each do |column| %><%= content_tag 'td', column_content(column, issue), :class => column.name %><% end %> |
|
| 12 |
</tr> |
|
| 13 |
<% end -%> |
|
| b/app/views/issues/context_menu.rhtml | ||
|---|---|---|
| 15 | 15 |
<li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)},
|
| 16 | 16 |
:class => 'icon-edit', :disabled => !@can[:edit] %></li> |
| 17 | 17 |
<% end %> |
| 18 | ||
| 19 | 18 |
<li class="folder"> |
| 20 | 19 |
<a href="#" class="submenu"><%= l(:field_priority) %></a> |
| 21 | 20 |
<ul> |
| ... | ... | |
| 64 | 63 |
</ul> |
| 65 | 64 |
</li> |
| 66 | 65 |
<% end -%> |
| 66 |
<% if @issue && @issue.edge? %> |
|
| 67 | 67 |
<li class="folder"> |
| 68 | 68 |
<a href="#" class="submenu"><%= l(:field_done_ratio) %></a> |
| 69 | 69 |
<ul> |
| ... | ... | |
| 73 | 73 |
<% end -%> |
| 74 | 74 |
</ul> |
| 75 | 75 |
</li> |
| 76 |
|
|
| 76 |
<% end %> |
|
| 77 | 77 |
<% if !@issue.nil? %> |
| 78 | 78 |
<li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
|
| 79 | 79 |
:class => 'icon-copy', :disabled => !@can[:copy] %></li> |
| b/app/views/issues/index.rfpdf | ||
|---|---|---|
| 24 | 24 |
pdf.Cell(30, row_height, l(:field_priority), 0, 0, 'L', 1) |
| 25 | 25 |
pdf.Cell(40, row_height, l(:field_assigned_to), 0, 0, 'L', 1) |
| 26 | 26 |
pdf.Cell(25, row_height, l(:field_updated_on), 0, 0, 'L', 1) |
| 27 |
pdf.Cell(15, row_height, l(:field_parent_issue), 0, 0, 'L', 1) |
|
| 27 | 28 |
pdf.Cell(0, row_height, l(:field_subject), 0, 0, 'L', 1) |
| 28 | 29 |
pdf.Line(10, pdf.GetY, 287, pdf.GetY) |
| 29 | 30 |
pdf.Ln |
| ... | ... | |
| 42 | 43 |
pdf.Cell(30, row_height, issue.priority.name, 0, 0, 'L', 1) |
| 43 | 44 |
pdf.Cell(40, row_height, issue.assigned_to ? issue.assigned_to.name : '', 0, 0, 'L', 1) |
| 44 | 45 |
pdf.Cell(25, row_height, format_date(issue.updated_on), 0, 0, 'L', 1) |
| 46 |
pdf.Cell(15, row_height, issue.parent ? "# #{issue.parent.id}" : '', 0, 0, 'L', 1)
|
|
| 45 | 47 |
pdf.MultiCell(0, row_height, (@project == issue.project ? issue.subject : "#{issue.project.name} - #{issue.subject}"))
|
| 46 | 48 |
pdf.Line(10, pdf.GetY, 287, pdf.GetY) |
| 47 | 49 |
pdf.SetY(pdf.GetY() + 1) |
| b/app/views/issues/show.rhtml | ||
|---|---|---|
| 1 | 1 |
<div class="contextual"> |
| 2 |
<%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
|
|
| 2 |
<%= link_to_if_authorized(l(:button_add_subissue), |
|
| 3 |
{ :controller => 'issues', :action => 'add_subissue',
|
|
| 4 |
:project_id => @project.id, :issue_parent_issue_id => @issue.id }, |
|
| 5 |
:class => 'icon icon-add') %> |
|
| 6 |
<%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue, :project_id => @project }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
|
|
| 3 | 7 |
<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time' %>
|
| 4 | 8 |
<%= watcher_tag(@issue, User.current) %> |
| 5 | 9 |
<%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-copy' %>
|
| ... | ... | |
| 51 | 55 |
if (n > 1) |
| 52 | 56 |
n = 0 %> |
| 53 | 57 |
</tr><tr> |
| 54 |
<%end
|
|
| 55 |
end %> |
|
| 58 |
<% end %>
|
|
| 59 |
<% end %>
|
|
| 56 | 60 |
</tr> |
| 57 | 61 |
<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %> |
| 58 | 62 |
</table> |
| b/app/views/projects/roadmap.rhtml | ||
|---|---|---|
| 10 | 10 |
<%= render :partial => 'versions/overview', :locals => {:version => version} %>
|
| 11 | 11 |
<%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %>
|
| 12 | 12 | |
| 13 |
<% issues = version.fixed_issues.find(:all, |
|
| 14 |
:include => [:status, :tracker], |
|
| 15 |
:conditions => ["tracker_id in (#{@selected_tracker_ids.join(',')})"],
|
|
| 16 |
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") unless @selected_tracker_ids.empty?
|
|
| 13 |
<% |
|
| 14 |
unless @selected_tracker_ids.empty? |
|
| 15 |
issues = version.fixed_issues.find(:all, |
|
| 16 |
:include => [:status, :tracker], |
|
| 17 |
:conditions => ["tracker_id in (#{@selected_tracker_ids.join(',')})"],
|
|
| 18 |
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id")
|
|
| 19 |
issues = Issue.find_with_parents( issues.collect { |i| i.id })
|
|
| 20 |
end |
|
| 17 | 21 |
issues ||= [] |
| 18 | 22 |
%> |
| 19 | 23 |
<% if issues.size > 0 %> |
| 20 | 24 |
<fieldset class="related-issues"><legend><%= l(:label_related_issues) %></legend> |
| 21 |
<ul> |
|
| 22 |
<%- issues.each do |issue| -%> |
|
| 23 |
<li><%= link_to_issue(issue) %>: <%=h issue.subject %></li> |
|
| 24 |
<%- end -%> |
|
| 25 |
</ul> |
|
| 25 |
<%= render_list_of_related_issues( issues, version) %> |
|
| 26 | 26 |
</fieldset> |
| 27 | 27 |
<% end %> |
| 28 | 28 |
<% end %> |
| b/app/views/versions/show.rhtml | ||
|---|---|---|
| 31 | 31 |
<%= render :partial => 'versions/overview', :locals => {:version => @version} %>
|
| 32 | 32 |
<%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %>
|
| 33 | 33 | |
| 34 |
<% issues = @version.fixed_issues.find(:all, |
|
| 35 |
:include => [:status, :tracker], |
|
| 36 |
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") %>
|
|
| 37 |
<% if issues.size > 0 %> |
|
| 34 |
<% if @issues.size > 0 %> |
|
| 38 | 35 |
<fieldset class="related-issues"><legend><%= l(:label_related_issues) %></legend> |
| 39 |
<ul> |
|
| 40 |
<% issues.each do |issue| -%> |
|
| 41 |
<li><%= link_to_issue(issue) %>: <%=h issue.subject %></li> |
|
| 42 |
<% end -%> |
|
| 43 |
</ul> |
|
| 36 |
<%= render_list_of_related_issues( @issues, @version) %> |
|
| 44 | 37 |
</fieldset> |
| 45 | 38 |
<% end %> |
| 46 | 39 |
</div> |
| b/config/boot.rb | ||
|---|---|---|
| 1 | 1 |
# Don't change this file! |
| 2 | 2 |
# Configure your app in config/environment.rb and config/environments/*.rb |
| 3 | 3 | |
| 4 |
RAILS_ROOT = File.expand_path("#{File.dirname(__FILE__)}/..") unless defined?(RAILS_ROOT)
|
|
| 4 |
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
|
|
| 5 | 5 | |
| 6 | 6 |
module Rails |
| 7 | 7 |
class << self |
| ... | ... | |
| 82 | 82 | |
| 83 | 83 |
def load_rubygems |
| 84 | 84 |
require 'rubygems' |
| 85 | ||
| 86 |
unless rubygems_version >= '0.9.4'
|
|
| 87 |
$stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.)
|
|
| 85 |
min_version = '1.1.1' |
|
| 86 |
unless rubygems_version >= min_version
|
|
| 87 |
$stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
|
|
| 88 | 88 |
exit 1 |
| 89 | 89 |
end |
| 90 | 90 | |
| 91 | 91 |
rescue LoadError |
| 92 |
$stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org)
|
|
| 92 |
$stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
|
|
| 93 | 93 |
exit 1 |
| 94 | 94 |
end |
| 95 | 95 | |
| b/lang/bg.yml | ||
|---|---|---|
| 119 | 119 |
field_assigned_to: Възложена на |
| 120 | 120 |
field_priority: Приоритет |
| 121 | 121 |
field_fixed_version: Планувана версия |
| 122 |
field_parent_issue: Child of |
|
| 122 | 123 |
field_user: Потребител |
| 123 | 124 |
field_role: Роля |
| 124 | 125 |
field_homepage: Начална страница |
| ... | ... | |
| 396 | 397 |
label_blocked_by: блокирана от |
| 397 | 398 |
label_precedes: предшества |
| 398 | 399 |
label_follows: изпълнява се след |
| 400 |
label_parents: child of |
|
| 401 |
label_children: parent of |
|
| 399 | 402 |
label_end_to_start: end to start |
| 400 | 403 |
label_end_to_end: end to end |
| 401 | 404 |
label_start_to_start: start to start |
| ... | ... | |
| 618 | 621 |
setting_default_projects_public: Новите проекти са публични по подразбиране |
| 619 | 622 |
error_scm_annotate: "Обектът не съществува или не може да бъде анотиран." |
| 620 | 623 |
label_planning: Планиране |
| 624 |
error_issue_can_have_only_one_parent: allows only one relationship (a task can have only one parent). |
|
| 621 | 625 |
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' |
| 622 | 626 |
label_and_its_subprojects: %s and its subprojects |
| 623 | 627 |
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" |
| ... | ... | |
| 692 | 696 |
text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." |
| 693 | 697 |
permission_edit_own_messages: Edit own messages |
| 694 | 698 |
permission_delete_own_messages: Delete own messages |
| 699 | ||
| 700 |
button_add_subissue: Add sub-issue |
|
| 701 |
field_calendar_firstday: First day of week |
|
| b/lang/ca.yml | ||
|---|---|---|
| 693 | 693 |
text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." |
| 694 | 694 |
permission_edit_own_messages: Edit own messages |
| 695 | 695 |
permission_delete_own_messages: Delete own messages |
| 696 | ||
| 697 |
button_add_subissue: Add sub-issue |
|
| 698 |
label_parents: child of |
|
| 699 |
label_children: parent of |
|
| 700 |
field_parent_issue: Child of |
|
| 701 |
error_issue_can_have_only_one_parent: allows only one relation (a task can have only one parent). |
|
| 702 |
field_calendar_firstday: First day of week |
|
| b/lang/cs.yml | ||
|---|---|---|
| 133 | 133 |
field_assigned_to: Přiřazeno |
| 134 | 134 |
field_priority: Priorita |
| 135 | 135 |
field_fixed_version: Přiřazeno k verzi |
| 136 |
field_parent_issue: Child of |
|
| 136 | 137 |
field_user: Uživatel |
| 137 | 138 |
field_role: Role |
| 138 | 139 |
field_homepage: Homepage |
| ... | ... | |
| 453 | 454 |
label_blocked_by: zablokován |
| 454 | 455 |
label_precedes: předchází |
| 455 | 456 |
label_follows: následuje |
| 457 |
label_parents: child of |
|
| 458 |
label_children: parent of |
|
| 456 | 459 |
label_end_to_start: od konce do začátku |
| 457 | 460 |
label_end_to_end: od konce do konce |
| 458 | 461 |
label_start_to_start: od začátku do začátku |
| ... | ... | |
| 623 | 626 |
enumeration_activities: Aktivity (sledování času) |
| 624 | 627 |
error_scm_annotate: "Položka neexistuje nebo nemůže být komentována." |
| 625 | 628 |
label_planning: Plánování |
| 629 |
error_issue_can_have_only_one_parent: allows only one relation (a task can have only one parent). |
|
| 626 | 630 |
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' |
| 627 | 631 |
label_and_its_subprojects: %s and its subprojects |
| 628 | 632 |
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" |
| ... | ... | |
| 697 | 701 |
text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." |
| 698 | 702 |
permission_edit_own_messages: Edit own messages |
| 699 | 703 |
permission_delete_own_messages: Delete own messages |
| 704 | ||
| 705 |
button_add_subissue: Add sub-issue |
|
| 706 |
field_calendar_firstday: First day of week |
|
| b/lang/da.yml | ||
|---|---|---|
| 133 | 133 |
field_assigned_to: Tildelt til |
| 134 | 134 |
field_priority: Prioritet |
| 135 | 135 |
field_fixed_version: Planlagt version |
| 136 |
field_parent_issue: Child of |
|
| 136 | 137 |
field_user: Bruger |
| 137 | 138 |
field_role: Rolle |
| 138 | 139 |
field_homepage: Hjemmeside |
| ... | ... | |
| 463 | 464 |
label_blocked_by: blokeret af |
| 464 | 465 |
label_precedes: kommer før |
| 465 | 466 |
label_follows: følger |
| 467 |
label_parents: child of |
|
| 468 |
label_children: parent of |
|
| 466 | 469 |
label_end_to_start: slut til start |
| 467 | 470 |
label_end_to_end: slut til slut |
| 468 | 471 |
label_start_to_start: start til start |
| ... | ... | |
| 524 | 527 |
label_chronological_order: I kronologisk rækkefølge |
| 525 | 528 |
label_reverse_chronological_order: I omvendt kronologisk rækkefølge |
| 526 | 529 |
label_planning: Planlægning |
| 530 |
error_issue_can_have_only_one_parent: allows only one relation (a task can have only one parent). |
|
| 527 | 531 |
label_incoming_emails: Indkommende e-mails |
| 528 | 532 |
label_generate_key: Generer en nøgle |
| 529 | 533 |
label_issue_watchers: Overvågere |
| ... | ... | |
| 693 | 697 |
text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." |
| 694 | 698 |
permission_edit_own_messages: Edit own messages |
| 695 | 699 |
permission_delete_own_messages: Delete own messages |
| 700 | ||
| 701 |
button_add_subissue: Add sub-issue |
|
| 702 |
field_calendar_firstday: First day of week |
|
| b/lang/de.yml | ||
|---|---|---|
| 133 | 133 |
field_assigned_to: Zugewiesen an |
| 134 | 134 |
field_priority: Priorität |
| 135 | 135 |
field_fixed_version: Zielversion |
| 136 |
field_parent_issue: Child of |
|
| 136 | 137 |
field_user: Benutzer |
| 137 | 138 |
field_role: Rolle |
| 138 | 139 |
field_homepage: Projekt-Homepage |
| ... | ... | |
| 514 | 515 |
label_blocked_by: Blockiert durch |
| 515 | 516 |
label_precedes: Vorgänger von |
| 516 | 517 |
label_follows: folgt |
| 518 |
label_parents: child of |
|
| 519 |
label_children: parent of |
|
| 517 | 520 |
label_end_to_start: Ende - Anfang |
| 518 | 521 |
label_end_to_end: Ende - Ende |
| 519 | 522 |
label_start_to_start: Anfang - Anfang |
| ... | ... | |
| 694 | 697 |
enumeration_issue_priorities: Ticket-Prioritäten |
| 695 | 698 |
enumeration_doc_categories: Dokumentenkategorien |
| 696 | 699 |
enumeration_activities: Aktivitäten (Zeiterfassung) |
| 700 | ||
| 701 |
error_issue_can_have_only_one_parent: allows only one relation (a task can have only one parent). |
|
| 702 | ||
| 703 |
button_add_subissue: Add sub-issue |
|
| 704 |
field_calendar_firstday: First day of week |
|
| b/lang/en.yml | ||
|---|---|---|
| 133 | 133 |
field_assigned_to: Assigned to |
| 134 | 134 |
field_priority: Priority |
| 135 | 135 |
field_fixed_version: Target version |
| 136 |
field_parent_issue: Child of |
|
| 136 | 137 |
field_user: User |
| 137 | 138 |
field_role: Role |
| 138 | 139 |
field_homepage: Homepage |
| ... | ... | |
| 184 | 185 |
field_default_value: Default value |
| 185 | 186 |
field_comments_sorting: Display comments |
| 186 | 187 |
field_parent_title: Parent page |
| 187 | ||
| 188 |
field_calendar_firstday: First day of week |
|
| 189 |
|
|
| 188 | 190 |
setting_app_title: Application title |
| 189 | 191 |
setting_app_subtitle: Application subtitle |
| 190 | 192 |
setting_welcome_text: Welcome text |
| ... | ... | |
| 514 | 516 |
label_blocked_by: blocked by |
| 515 | 517 |
label_precedes: precedes |
| 516 | 518 |
label_follows: follows |
| 519 |
label_parents: child of |
|
| 520 |
label_children: parent of |
|
| 517 | 521 |
label_end_to_start: end to start |
| 518 | 522 |
label_end_to_end: end to end |
| 519 | 523 |
label_start_to_start: start to start |
| ... | ... | |
| 590 | 594 |
button_test: Test |
| 591 | 595 |
button_edit: Edit |
| 592 | 596 |
button_add: Add |
| 597 |
button_add_subissue: Add sub-issue |
|
| 593 | 598 |
button_change: Change |
| 594 | 599 |
button_apply: Apply |
| 595 | 600 |
button_clear: Clear |
| ... | ... | |
| 627 | 632 |
text_regexp_info: eg. ^[A-Z0-9]+$ |
| 628 | 633 |
text_min_max_length_info: 0 means no restriction |
| 629 | 634 |
text_project_destroy_confirmation: Are you sure you want to delete this project and related data ? |
| 635 |
error_issue_can_have_only_one_parent: allows only one relation (a task can have only one parent). |
|
| 630 | 636 |
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' |
| 631 | 637 |
text_workflow_edit: Select a role and a tracker to edit the workflow |
| 632 | 638 |
text_are_you_sure: Are you sure ? |
| b/lang/es.yml | ||
|---|---|---|
| 137 | 137 |
field_identifier: Identificador |
| 138 | 138 |
field_is_closed: Petición resuelta |
| 139 | 139 |
field_is_default: Estado por defecto |
| 140 |
field_is_filter: Usado como filtro |
|
| 141 |
field_is_for_all: Para todos los proyectos |
|
| 142 | 140 |
field_is_in_chlog: Consultar las peticiones en el histórico |
| 143 | 141 |
field_is_in_roadmap: Consultar las peticiones en el roadmap |
| 144 | 142 |
field_is_public: Público |
| ... | ... | |
| 185 | 183 |
field_user: Usuario |
| 186 | 184 |
field_value: Valor |
| 187 | 185 |
field_version: Versión |
| 186 |
field_parent: Proyecto padre |
|
| 187 |
field_parent_issue: Child of |
|
| 188 | 188 |
general_csv_decimal_separator: ',' |
| 189 | 189 |
general_csv_encoding: ISO-8859-15 |
| 190 | 190 |
general_csv_separator: ';' |
| ... | ... | |
| 501 | 501 |
label_workflow: Flujo de trabajo |
| 502 | 502 |
label_year: Año |
| 503 | 503 |
label_yesterday: ayer |
| 504 |
label_parents: child of |
|
| 505 |
label_children: parent of |
|
| 504 | 506 |
mail_body_account_activation_request: "Un nuevo usuario (%s) ha sido registrado. Esta cuenta está pendiende de aprobación" |
| 505 | 507 |
mail_body_account_information: Información sobre su cuenta |
| 506 | 508 |
mail_body_account_information_external: Puede usar su cuenta "%s" para conectarse. |
| ... | ... | |
| 592 | 594 |
project_module_time_tracking: Control de tiempo |
| 593 | 595 |
project_module_wiki: Wiki |
| 594 | 596 |
setting_activity_days_default: Días a mostrar en la actividad de proyecto |
| 595 |
setting_app_subtitle: Subtítulo de la aplicación |
|
| 596 |
setting_app_title: Título de la aplicación |
|
| 597 |
setting_attachment_max_size: Tamaño máximo del fichero |
|
| 598 |
setting_autofetch_changesets: Autorellenar los commits del repositorio |
|
| 599 |
setting_autologin: Conexión automática |
|
| 600 |
setting_bcc_recipients: Ocultar las copias de carbón (bcc) |
|
| 601 |
setting_commit_fix_keywords: Palabras clave para la corrección |
|
| 602 |
setting_commit_logs_encoding: Codificación de los mensajes de commit |
|
| 603 |
setting_commit_ref_keywords: Palabras clave para la referencia |
|
| 604 |
setting_cross_project_issue_relations: Permitir relacionar peticiones de distintos proyectos |
|
| 605 |
setting_date_format: Formato de la fecha |
|
| 606 |
setting_default_language: Idioma por defecto |
|
| 607 |
setting_default_projects_public: Los proyectos nuevos son públicos por defecto |
|
| 608 |
setting_display_subprojects_issues: Mostrar peticiones de un subproyecto en el proyecto padre por defecto |
|
| 609 |
setting_emails_footer: Pie de mensajes |
|
| 597 | ||
| 598 |
error_issue_can_have_only_one_parent: allows only one relation (a task can have only one parent). |
|
| 599 | ||
| 610 | 600 |
setting_enabled_scm: Activar SCM |
| 611 | 601 |
setting_feeds_limit: Límite de contenido para sindicación |
| 612 | 602 |
setting_gravatar_enabled: Usar iconos de usuario (Gravatar) |
| ... | ... | |
| 677 | 667 |
text_user_wrote: '%s escribió:' |
| 678 | 668 |
text_wiki_destroy_confirmation: ¿Seguro que quiere borrar el wiki y todo su contenido? |
| 679 | 669 |
text_workflow_edit: Seleccionar un flujo de trabajo para actualizar |
| 670 |
field_is_filter: Used as a filter |
|
| 671 |
setting_default_language: Default language |
|
| 672 |
setting_emails_footer: Emails footer |
|
| 673 |
setting_app_subtitle: Application subtitle |
|
| 674 |
button_add_subissue: Add sub-issue |
|
| 675 |
setting_cross_project_issue_relations: Allow cross-project issue relations |
|
| 676 |
setting_autofetch_changesets: Autofetch commits |
|
| 677 |
setting_attachment_max_size: Attachment max. size |
|
| 678 |
setting_app_title: Application title |
|
| 679 |
setting_date_format: Date format |
|
| 680 |
setting_default_projects_public: New projects are public by default |
|
| 681 |
setting_commit_fix_keywords: Fixing keywords |
|
| 682 |
setting_autologin: Autologin |
|
| 683 |
setting_display_subprojects_issues: Display subprojects issues on main projects by default |
|
| 684 |
setting_bcc_recipients: Blind carbon copy recipients (bcc) |
|
| 685 |
setting_commit_ref_keywords: Referencing keywords |
|
| 686 |
field_is_for_all: For all projects |
|
| 687 |
setting_commit_logs_encoding: Commit messages encoding |
|
| 688 |
field_calendar_firstday: First day of week |
|
| b/lang/fi.yml | ||
|---|---|---|
| 692 | 692 |
text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." |
| 693 | 693 |
permission_edit_own_messages: Edit own messages |
| 694 | 694 |
permission_delete_own_messages: Delete own messages |
| 695 | ||
| 696 |
button_add_subissue: Add sub-issue |
|
| 697 |
label_parents: child of |
|
| 698 |
label_children: parent of |
|
| 699 |
field_parent_issue: Child of |
|
| 700 |
error_issue_can_have_only_one_parent: allows only one relation (a task can have only one parent). |
|
| 701 |
field_calendar_firstday: First day of week |
|
| b/lang/fr.yml | ||
|---|---|---|
| 133 | 133 |
field_assigned_to: Assigné à |
| 134 | 134 |
field_priority: Priorité |
| 135 | 135 |
field_fixed_version: Version cible |
| 136 |
field_parent_issue: Child of |
|
| 136 | 137 |
field_user: Utilisateur |
| 137 | 138 |
field_role: Rôle |
| 138 | 139 |
field_homepage: Site web |
| ... | ... | |
| 514 | 515 |
label_blocked_by: bloqué par |
| 515 | 516 |
label_precedes: précède |
| 516 | 517 |
label_follows: suit |
| 518 |
label_parents: child of |
|
| 519 |
label_children: parent of |
|
| 517 | 520 |
label_end_to_start: fin à début |
| 518 | 521 |
label_end_to_end: fin à fin |
| 519 | 522 |
label_start_to_start: début à début |
| ... | ... | |
| 627 | 630 |
text_regexp_info: ex. ^[A-Z0-9]+$ |
| 628 | 631 |
text_min_max_length_info: 0 pour aucune restriction |
| 629 | 632 |
text_project_destroy_confirmation: Etes-vous sûr de vouloir supprimer ce projet et toutes ses données ? |
| 633 |
error_issue_can_have_only_one_parent: allows only one relation (a task can have only one parent). |
|
| 630 | 634 |
text_subprojects_destroy_warning: 'Ses sous-projets: %s seront également supprimés.' |
| 631 | 635 |
text_workflow_edit: Sélectionner un tracker et un rôle pour éditer le workflow |
| 632 | 636 |
text_are_you_sure: Etes-vous sûr ? |
| ... | ... | |
| 694 | 698 |
enumeration_issue_priorities: Priorités des demandes |
| 695 | 699 |
enumeration_doc_categories: Catégories des documents |
| 696 | 700 |
enumeration_activities: Activités (suivi du temps) |
| 701 |
button_add_subissue: Add sub-issue |
|
| 702 |
field_calendar_firstday: First day of week |
|
| b/lang/he.yml | ||
|---|---|---|
| 121 | 121 |
field_assigned_to: מוצב ל |
| 122 | 122 |
field_priority: עדיפות |
| 123 | 123 |
field_fixed_version: גירסאת יעד |
| 124 |
field_parent_issue: Child of |
|
| 124 | 125 |
field_user: מתשמש |
| 125 | 126 |
field_role: תפקיד |
| 126 | 127 |
field_homepage: דף הבית |
| ... | ... | |
| 618 | 619 |
setting_default_projects_public: פרויקטים חדשים הינם פומביים כברירת מחדל |
| 619 | 620 |
error_scm_annotate: "הכניסה לא קיימת או שלא ניתן לתאר אותה." |
| 620 | 621 |
label_planning: תכנון |
| 622 |
error_issue_can_have_only_one_parent: allows only one relation (a task can have only one parent). |
|
| 621 | 623 |
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' |
| 622 | 624 |
label_and_its_subprojects: %s and its subprojects |
| 623 | 625 |
mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" |
| ... | ... | |
| 692 | 694 |
text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." |
| 693 | 695 |
permission_edit_own_messages: Edit own messages |
| 694 | 696 |
permission_delete_own_messages: Delete own messages |
| 697 | ||
| 698 |
button_add_subissue: Add sub-issue |
|
| 699 |
label_parents: child of |
|
| 700 |
label_children: parent of |
|
| 701 |
field_calendar_firstday: First day of week |
|
| b/lang/hu.yml | ||
|---|---|---|
| 693 | 693 |
text_repository_usernames_mapping: "Állítsd be a felhasználó összerendeléseket a Redmine, és a tároló logban található felhasználók között.\nAz azonos felhasználó nevek összerendelése automatikusan megtörténik." |
| 694 | 694 |
permission_edit_own_messages: Saját üzenetek szerkesztése |
| 695 | 695 |
permission_delete_own_messages: Saját üzenetek törlése |
| 696 | ||
| 697 |
button_add_subissue: Add sub-issue |
|
| 698 |
label_parents: child of |
|
| 699 |
label_children: parent of |
|
| 700 |
field_parent_issue: Child of |
|
| 701 |
error_issue_can_have_only_one_parent: allows only one relation (a task can have only one parent). |
|
| 702 |
field_calendar_firstday: First day of week |
|
| b/lang/it.yml | ||
|---|---|---|
| 119 | 119 |
field_assigned_to: Assegnato a |
| 120 | 120 |
field_priority: Priorita' |
| 121 | 121 |
field_fixed_version: Versione prevista |
| 122 |
field_parent_issue: Child of |
|
| 122 | 123 |
field_user: Utente |
| 123 | 124 |
field_role: Ruolo |
| 124 | 125 |
field_homepage: Homepage |
| ... | ... | |
| 396 | 397 |
label_blocked_by: bloccato da |
| 397 | 398 |
label_precedes: precede |
| 398 | 399 |
label_follows: segue |
| 400 |
label_parents: child of |
|
| 401 |
label_children: parent of |
|
| 399 | 402 |
label_end_to_start: end to start |
| 400 | 403 |
label_end_to_end: end to end |
| 401 | 404 |
label_start_to_start: start to start |
| ... | ... | |
| 618 | 621 |
setting_default_projects_public: I nuovi progetti sono pubblici per default |
| 619 | 622 |
error_scm_annotate: "L'oggetto non esiste o non può essere annotato." |
| 620 | 623 |
label_planning: Pianificazione |
| 624 |
error_issue_can_have_only_one_parent: allows only one relation (a task can have only one parent). |
|
| 621 | 625 |
text_subprojects_destroy_warning: 'Anche i suoi sottoprogetti: %s verranno eliminati.' |
| 622 | 626 |
label_and_its_subprojects: %s ed i suoi sottoprogetti |
| 623 | 627 |
mail_body_reminder: "%d segnalazioni che ti sono state assegnate scadranno nei prossimi %d giorni:" |
| ... | ... | |
| 692 | 696 |
text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." |
| 693 | 697 |
permission_edit_own_messages: Edit own messages |
| 694 | 698 |
permission_delete_own_messages: Delete own messages |
| 699 | ||
| 700 |
button_add_subissue: Add sub-issue |
|
| 701 |
field_calendar_firstday: First day of week |
|