Index: app/controllers/issues_controller.rb
===================================================================
--- app/controllers/issues_controller.rb (revision 2671)
+++ app/controllers/issues_controller.rb (working copy)
@@ -18,10 +18,10 @@
class IssuesController < ApplicationController
menu_item :new_issue, :only => :new
- before_filter :find_issue, :only => [:show, :edit, :reply]
+ before_filter :find_issue, :only => [:show, :edit, :reply, :edit_gantt]
before_filter :find_issues, :only => [:bulk_edit, :move, :destroy]
before_filter :find_project, :only => [:new, :update_form, :preview]
- before_filter :authorize, :except => [:index, :changes, :gantt, :calendar, :preview, :update_form, :context_menu]
+ before_filter :authorize, :except => [:index, :changes, :gantt, :calendar, :preview, :update_form, :context_menu, :edit_gantt]
before_filter :find_optional_project, :only => [:index, :changes, :gantt, :calendar]
accept_key_auth :index, :changes
@@ -159,6 +159,64 @@
# Attributes that can be updated on workflow transition (without :edit permission)
# TODO: make it configurable (at least per role)
UPDATABLE_ATTRS_ON_TRANSITION = %w(status_id assigned_to_id fixed_version_id done_ratio) unless const_defined?(:UPDATABLE_ATTRS_ON_TRANSITION)
+
+ def edit_gantt
+ if !@issue.start_date || !@issue.due_before
+ render :text=>l(:notice_locking_conflict), :status=>400
+ return
+ end
+ @issue.init_journal(User.current)
+ date_from = Date.parse(params[:date_from])
+ old_start_date = @issue.start_date
+ o = get_position(@issue, date_from, Date.parse(params[:date_to]), params[:zoom])
+ text_for_revert = "#{@issue.id}=#{format_date(@issue.start_date)},#{@issue.start_date},#{format_date(@issue.due_before)},#{@issue.due_before},#{o[0]},#{o[1]},#{o[2]},#{o[3]}"
+
+ if params[:day]
+ #bar moved
+ day = params[:day].to_i
+ duration = @issue.due_before - @issue.start_date
+ @issue.start_date = date_from + day
+ @issue.due_date = @issue.start_date + duration.to_i if @issue.due_date
+ elsif params[:start_date]
+ #start date changed
+ start_date = Date.parse(params[:start_date])
+ if @issue.start_date == start_date
+ render :text=>""
+ return #nothing has changed
+ end
+ @issue.start_date = start_date
+ @issue.due_date = start_date if @issue.due_date && start_date > @issue.due_date
+ elsif params[:due_date]
+ #due date changed
+ due_date = Date.parse(params[:due_date])
+ if @issue.due_date == due_date
+ render :text=>""
+ return #nothing has changed
+ end
+ @issue.due_date = due_date
+ @issue.start_date = due_date if due_date < @issue.start_date
+ end
+ fv = @issue.fixed_version
+ if fv && fv.effective_date && !@issue.due_date && fv.effective_date < @issue.start_date
+ @issue.start_date = old_start_date
+ end
+
+ begin
+ @issue.save!
+ o = get_position(@issue, date_from, Date.parse(params[:date_to]), params[:zoom])
+ text = "#{@issue.id}=#{format_date(@issue.start_date)},#{@issue.start_date},#{format_date(@issue.due_before)},#{@issue.due_before},#{o[0]},#{o[1]},#{o[2]},#{o[3]}"
+
+ #check dependencies
+ issues = @issue.all_precedes_issues
+ issues.each do |i|
+ o = get_position(i, date_from, Date.parse(params[:date_to]), params[:zoom])
+ text += "|#{i.id}=#{format_date(i.start_date)},#{i.start_date},#{format_date(i.due_before)},#{i.due_before},#{o[0]},#{o[1]},#{o[2]},#{o[3]}"
+ end
+ render :text=>text
+ rescue
+ render :text=>@issue.errors.full_messages.join("\n") + "|" + text_for_revert , :status=>400
+ end
+ end
def edit
@allowed_statuses = @issue.new_statuses_allowed_to(User.current)
Index: app/helpers/issues_helper.rb
===================================================================
--- app/helpers/issues_helper.rb (revision 2671)
+++ app/helpers/issues_helper.rb (working copy)
@@ -27,8 +27,8 @@
@cached_label_priority ||= l(:field_priority)
link_to_issue(issue) + ": #{h(issue.subject)}
" +
- "#{@cached_label_start_date}: #{format_date(issue.start_date)}
" +
- "#{@cached_label_due_date}: #{format_date(issue.due_date)}
" +
+ "#{@cached_label_start_date}: #{format_date(issue.start_date)}
" +
+ "#{@cached_label_due_date}: #{format_date(issue.due_date)}
" +
"#{@cached_label_assigned_to}: #{issue.assigned_to}
" +
"#{@cached_label_priority}: #{issue.priority.name}"
end
@@ -196,4 +196,26 @@
export.rewind
export
end
+
+ def get_position(event, date_from, date_to, zoom_str)
+ zoom = zoom_str.to_i
+ i_start_date = (event.start_date >= date_from ? event.start_date : date_from )
+ i_end_date = (event.due_before <= date_to ? event.due_before : date_to )
+
+ i_done_date = event.start_date + ((event.due_before - event.start_date+1)*event.done_ratio/100).floor
+ i_done_date = (i_done_date <= date_from ? date_from : i_done_date )
+ i_done_date = (i_done_date >= date_to ? date_to : i_done_date )
+
+ i_late_date = [i_end_date, Date.today].min if i_start_date <= Date.today
+
+ i_left = ((i_start_date - date_from)*zoom).floor
+ i_left = 0 if i_left < 0
+ i_width = ((i_end_date - i_start_date + 1)*zoom).floor - 2 # total width of the issue (- 2 for left and right borders)
+ i_width = 0 if i_width < 0
+ d_width = ((i_done_date - i_start_date)*zoom).floor - 2 # done width
+ d_width = 0 if d_width < 0
+ l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width
+ l_width = 0 if l_width < 0
+ return i_left, i_width, l_width, d_width
+ end
end
Index: app/models/issue.rb
===================================================================
--- app/models/issue.rb (revision 2671)
+++ app/models/issue.rb (working copy)
@@ -240,6 +240,16 @@
end
dependencies
end
+
+ def all_precedes_issues
+ dependencies = []
+ relations_from.each do |relation|
+ next unless relation.relation_type == IssueRelation::TYPE_PRECEDES
+ dependencies << relation.issue_to
+ dependencies += relation.issue_to.all_dependent_issues
+ end
+ dependencies
+ end
# Returns an array of issues that duplicate this one
def duplicates
Index: app/views/issues/gantt.rhtml
===================================================================
--- app/views/issues/gantt.rhtml (revision 2671)
+++ app/views/issues/gantt.rhtml (working copy)
@@ -1,3 +1,4 @@
+<% include_calendar_headers_tags %>
<% form_tag(params.merge(:month => nil, :year => nil, :months => nil), :id => 'query_form') do %>
<% if @query.new_record? %>
@@ -83,7 +178,7 @@ # top = headers_height + 8 @gantt.events.each do |i| %> - | +
+
+
+
+<%
+top = headers_height + 8
+@gantt.events.each do |i| %>
+
+
+ <%= format_date(i.start_date) %>
+
+ <%= calendar_for("#{i.id}_start_date") if i.is_a? Issue %>
+
+ <% if i.is_a? Issue %>
+ ">
+ <%= format_date(i.due_before) %>
+
+
+ <%= calendar_for("#{i.id}_due_date") if i.due_date%>
+
+ <% end %>
+
+<% top = top + 20
+end %>
+ |
-
+
<%= link_to "#{month_f.year}-#{month_f.month}", @gantt.params.merge(:year => month_f.year, :month => month_f.month), :title => "#{month_name(month_f.month)} #{month_f.year}"%>
- <%
+ <%
left = left + width + 1
month_f = month_f >> 1
end %>
-<%
+<%
#
# Weeks headers
#
@@ -136,7 +276,7 @@
width = (7 - @gantt.date_from.cwday + 1) * zoom-1
%>
<%= week_f.cweek if width >= 16 %>
- <%
+ <%
left = left + width+1
week_f = week_f+7
end
end %>
-<%
+<%
#
# Days headers
#
@@ -160,15 +300,17 @@
left = 0
height = g_height + header_heigth - 1
wday = @gantt.date_from.cwday
- (@gantt.date_to - @gantt.date_from + 1).to_i.times do
+ dt = @gantt.date_from
+ (@gantt.date_to - @gantt.date_from + 1).to_i.times do
width = zoom - 1
%>
5 %>" class="gantt_hdr">
- <%= day_name(wday).first %>
+ <%= "#{dt.day}
- <%
+ <%
left = left + width+1
wday = wday + 1
+ dt = dt + 1
wday = 1 if wday > 7
end
end %>
@@ -178,41 +320,36 @@
# Tasks
#
top = headers_height + 10
-@gantt.events.each do |i|
- if i.is_a? Issue
- i_start_date = (i.start_date >= @gantt.date_from ? i.start_date : @gantt.date_from )
- i_end_date = (i.due_before <= @gantt.date_to ? i.due_before : @gantt.date_to )
-
- i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor
- i_done_date = (i_done_date <= @gantt.date_from ? @gantt.date_from : i_done_date )
- i_done_date = (i_done_date >= @gantt.date_to ? @gantt.date_to : i_done_date )
-
- i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
-
- i_left = ((i_start_date - @gantt.date_from)*zoom).floor
- i_width = ((i_end_date - i_start_date + 1)*zoom).floor - 2 # total width of the issue (- 2 for left and right borders)
- d_width = ((i_done_date - i_start_date)*zoom).floor - 2 # done width
- l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width
+@gantt.events.each do |i|
+ if i.is_a? Issue
+ i_left, i_width, l_width, d_width = get_position(i, @gantt.date_from, @gantt.date_to, zoom)
%>
- "if @gantt.zoom == 4 %><%= day_name(wday).first %>
- <%= i.status.name %>
- <%= (i.done_ratio).to_i %>%
-
-
-
+
+
+ <% # === tooltip === %>
+
+ <%= h(i.status.name) %>
+ <%= (i.done_ratio).to_i %>%
+ <% if !i.due_date && i.fixed_version %>
+ - <%= h(i.fixed_version.name) %>
+ <% end %>
+
+
+
<%= render_issue_tooltip i %>
-<% else
+ <%= draggable_element("ev_#{i.id}",
+ :revert =>false, :scroll=>"'gantt-container'", :constraint => "'horizontal'", :snap=>zoom,
+ :onEnd=>"function( draggable, event ) {issue_moved(draggable.element);}"
+ ) %>
+
+<% else
i_left = ((i.start_date - @gantt.date_from)*zoom).floor
%>
-
<%= h("#{i.project} -") unless @project && @project == i.project %>
<%=h i %>
Index: public/stylesheets/application.css
===================================================================
--- public/stylesheets/application.css (revision 2671)
+++ public/stylesheets/application.css (working copy)
@@ -639,6 +639,8 @@
.task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
.task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
.task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
+.task_none { background:transparent; border-style: none; }
+.task_none { background:transparent; border-style: none; }
.milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }
/***** Icons *****/
|