Bug #300: First shot at dependency entry in edit form

Limitations:
* No javascript update of dependency changes.
* No resolution for duplicate descriptions.

Conflicts:

	app/views/todos/_edit_form.rhtml
This commit is contained in:
Eric Allen 2009-11-04 22:39:19 -05:00
parent 45dd524519
commit 42cbe52224
4 changed files with 98 additions and 3 deletions

View file

@ -8,7 +8,7 @@ class TodosController < ApplicationController
:completed_archive, :check_deferred, :toggle_check, :toggle_star,
:edit, :update, :create, :calendar, :auto_complete_for_tag]
append_before_filter :get_todo_from_params, :only => [ :edit, :toggle_check, :toggle_star, :show, :update, :destroy ]
protect_from_forgery :except => [:auto_complete_for_tag]
protect_from_forgery :except => [:auto_complete_for_tag, :auto_complete_for_predecessor]
session :off, :only => :index, :if => Proc.new { |req| is_feed_request(req) }
@ -214,7 +214,25 @@ class TodosController < ApplicationController
@original_item_project_id = @todo.project_id
@original_item_was_deferred = @todo.deferred?
@original_item_due = @todo.due
@original_item_due_id = get_due_id_for_calendar(@todo.due)
@original_item_due_id = get_due_id_for_calendar(@todo.due)
@original_item_predecessor_list = @todo.predecessors.collect{|t| t.description}.join(', ')
if params[:predecessor_list]
logger.debug "---old #{@original_item_predecessor_list}"
logger.debug "---new #{params[:predecessor_list]}"
@todo.add_predecessor_list(params[:predecessor_list])
if @original_item_predecessor_list != params[:predecessor_list]
# Recalculate dependencies for this todo
if @todo.uncompleted_predecessors.empty?
if @todo.state == 'pending'
@todo.activate! # Activate pending if no uncompleted predecessors
end
else
if @todo.state == 'active'
@todo.block! # Block active if we got uncompleted predecessors
end
end
end
end
if params['todo']['project_id'].blank? && !params['project_name'].nil?
if params['project_name'] == 'None'
@ -540,6 +558,28 @@ class TodosController < ApplicationController
render :inline => "<%= auto_complete_result(@items, :name) %>"
end
def auto_complete_for_predecessor
get_todo_from_params
# Begin matching todos in current project
@items = current_user.todos.find(:all,
:conditions => [ 'NOT (id = ?) AND description LIKE ? AND project_id = ?',
@todo.id,
'%' + params[:predecessor_list] + '%',
@todo.project_id ],
:order => 'description ASC',
:limit => 10
)
if @items.empty? # Match todos in other projects
@items = current_user.todos.find(:all,
:conditions => [ 'NOT (id = ?) AND description LIKE ?',
params[:id], '%' + params[:predecessor_list] + '%' ],
:order => 'description ASC',
:limit => 10
)
end
render :inline => "<%= auto_complete_result(@items, :description) %>"
end
private
def get_todo_from_params

View file

@ -116,6 +116,20 @@ module TodosHelper
if tag_list.empty? then "" else "<span class=\"tags\">#{tag_list}</span>" end
end
# TODO: Use DELIMITER
def predecessor_list_text
@todo.predecessors.collect{|t| t.description}.join(', ')
end
def predecessor_list
predecessor_list = @todo.predecessors.collect{|t|
'<span class="predecessor #{t.description}">' +
link_to(t.name, :controller => "todos", :action => "tag", :id => t.name) +
"</span>"
}.join('')
'<span class="predecessors">#{predecessor_list}</span>'
end
def deferred_due_date
if @todo.deferred? && @todo.due
"(action due on #{format_date(@todo.due)})"

View file

@ -154,6 +154,39 @@ class Todo < ActiveRecord::Base
return self.recurring_todo_id != nil
end
def add_predecessor(predecessor)
logger.debug "add_predecessor #{predecessor.description}"
end
# TODO: DELIMITER
# TODO: Todo::Error
# TODO: Handle todos with the same description
def add_predecessor_list(predecessor_list)
logger.debug "add_predecessor_list #{predecessor_list}"
raise "Can't handle other types than string for now" unless predecessor_list.kind_of? String
list = predecessor_list.split(',').map do |description|
description.strip.squeeze(" ")
end
current = self.predecessors.map(&:description)
remove_list = current - list
# This is probably a bit naive code...
remove_list.each do |description|
t = Todo.find_by_description(description)
logger.debug "Removing #{t.description} from #{self.description} as predecessor"
self.predecessors.delete(t)
end
add_list = list - current
# ... as is this?
add_list.each do |description|
t = Todo.find_by_description(description)
#raise Todo::Error, "predecessor could not be found: #{description}" if t.nil?
# Create dependency record
self.predecessors << t unless self.predecessors.include?(t)
end
# debugger
end
# Rich Todo API
def self.from_rich_message(user, default_context_id, description, notes)

View file

@ -46,13 +46,21 @@
</a>
</div>
<label class="predecessor_list_label" for="<%= dom_id(@todo, 'predecessor_list') %>">Depends on (separate with commas)</label>
<%= text_field_tag 'predecessor_list', predecessor_list_text, :id => dom_id(@todo, 'predecessor_list'), :size => 30, :tabindex => 15 %>
<%= content_tag("div", "", :id => dom_id(@todo, 'predecessor_list')+"_auto_complete", :class => "auto_complete") %>
<%= auto_complete_field dom_id(@todo, 'predecessor_list'), {
:url => {:controller => 'todos', :action => 'auto_complete_for_predecessor', :id => @todo.id},
:tokens => [',']
} %>
<% if controller.controller_name == "project" || @todo.deferred? -%>
<input type="hidden" name="on_project_page" value="true" />
<% end -%>
<div class="submit_box">
<div class="widgets">
<button type="submit" class="positive" id="<%= dom_id(@todo, 'submit') %>" tabindex="15">
<button type="submit" class="positive" id="<%= dom_id(@todo, 'submit') %>" tabindex="16">
<%=image_tag("accept.png", :alt => "") %>
Update
</button>