mirror of
https://github.com/TracksApp/tracks.git
synced 2025-09-22 05:50:47 +02:00
Merge branch 'master' into rails4
Conflicts: Gemfile.lock config/routes.rb
This commit is contained in:
commit
4a485558e2
51 changed files with 5475 additions and 5015 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,6 +3,8 @@
|
|||
.dotest
|
||||
.idea
|
||||
.rvmrc
|
||||
.ruby-gemset
|
||||
.ruby-version
|
||||
.sass-cache/
|
||||
.yardoc
|
||||
/.bundle
|
||||
|
|
68
Gemfile.lock
68
Gemfile.lock
|
@ -9,9 +9,15 @@ GEM
|
|||
remote: https://rubygems.org/
|
||||
specs:
|
||||
RedCloth (4.2.9)
|
||||
<<<<<<< HEAD
|
||||
aasm (3.0.18)
|
||||
actionmailer (4.0.0.rc1)
|
||||
actionpack (= 4.0.0.rc1)
|
||||
=======
|
||||
aasm (3.0.19)
|
||||
actionmailer (3.2.13)
|
||||
actionpack (= 3.2.13)
|
||||
>>>>>>> master
|
||||
mail (~> 2.5.3)
|
||||
actionpack (4.0.0.rc1)
|
||||
activesupport (= 4.0.0.rc1)
|
||||
|
@ -36,7 +42,11 @@ GEM
|
|||
tzinfo (~> 0.3.37)
|
||||
acts_as_list (0.2.0)
|
||||
activerecord (>= 3.0)
|
||||
<<<<<<< HEAD
|
||||
arel (4.0.0)
|
||||
=======
|
||||
arel (3.0.2)
|
||||
>>>>>>> master
|
||||
aruba (0.5.3)
|
||||
childprocess (>= 0.3.6)
|
||||
cucumber (>= 1.1.1)
|
||||
|
@ -73,6 +83,10 @@ GEM
|
|||
capybara (>= 1.1.2)
|
||||
cucumber (>= 1.1.8)
|
||||
nokogiri (>= 1.5.0)
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
rails (~> 3.0)
|
||||
>>>>>>> master
|
||||
database_cleaner (1.0.1)
|
||||
diff-lcs (1.2.4)
|
||||
erubis (2.7.0)
|
||||
|
@ -83,33 +97,49 @@ GEM
|
|||
factory_girl_rails (4.2.1)
|
||||
factory_girl (~> 4.2.0)
|
||||
railties (>= 3.0.0)
|
||||
ffi (1.8.1)
|
||||
ffi (1.9.0)
|
||||
gherkin (2.12.0)
|
||||
multi_json (~> 1.3)
|
||||
hike (1.2.2)
|
||||
hike (1.2.3)
|
||||
htmlentities (4.3.1)
|
||||
<<<<<<< HEAD
|
||||
i18n (0.6.4)
|
||||
jquery-rails (2.2.1)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
=======
|
||||
i18n (0.6.1)
|
||||
journey (1.0.4)
|
||||
jquery-rails (3.0.1)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (1.8.0)
|
||||
>>>>>>> master
|
||||
libv8 (3.11.8.17)
|
||||
mail (2.5.4)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
metaclass (0.0.1)
|
||||
mime-types (1.23)
|
||||
<<<<<<< HEAD
|
||||
minitest (4.7.4)
|
||||
mocha (0.14.0)
|
||||
metaclass (~> 0.0.1)
|
||||
multi_json (1.7.3)
|
||||
=======
|
||||
mocha (0.14.0)
|
||||
metaclass (~> 0.0.1)
|
||||
multi_json (1.7.6)
|
||||
>>>>>>> master
|
||||
mysql2 (0.3.11)
|
||||
nokogiri (1.5.9)
|
||||
nokogiri (1.5.10)
|
||||
polyglot (0.3.3)
|
||||
rack (1.5.2)
|
||||
rack-mini-profiler (0.1.26)
|
||||
rack (>= 1.1.3)
|
||||
rack-test (0.6.2)
|
||||
rack (>= 1.0)
|
||||
<<<<<<< HEAD
|
||||
rails (4.0.0.rc1)
|
||||
actionmailer (= 4.0.0.rc1)
|
||||
actionpack (= 4.0.0.rc1)
|
||||
|
@ -123,23 +153,49 @@ GEM
|
|||
railties (4.0.0.rc1)
|
||||
actionpack (= 4.0.0.rc1)
|
||||
activesupport (= 4.0.0.rc1)
|
||||
=======
|
||||
rails (3.2.13)
|
||||
actionmailer (= 3.2.13)
|
||||
actionpack (= 3.2.13)
|
||||
activerecord (= 3.2.13)
|
||||
activeresource (= 3.2.13)
|
||||
activesupport (= 3.2.13)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.2.13)
|
||||
rails_autolink (1.1.0)
|
||||
rails (> 3.1)
|
||||
railties (3.2.13)
|
||||
actionpack (= 3.2.13)
|
||||
activesupport (= 3.2.13)
|
||||
rack-ssl (~> 1.3.2)
|
||||
>>>>>>> master
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rake (10.0.4)
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
>>>>>>> master
|
||||
ref (1.0.5)
|
||||
rspec-expectations (2.13.0)
|
||||
diff-lcs (>= 1.1.3, < 2.0)
|
||||
rubyzip (0.9.9)
|
||||
safe_yaml (0.9.1)
|
||||
safe_yaml (0.9.3)
|
||||
sanitize (2.0.3)
|
||||
nokogiri (>= 1.4.4, < 1.6)
|
||||
sass (3.2.9)
|
||||
<<<<<<< HEAD
|
||||
sass-rails (4.0.0.rc1)
|
||||
railties (>= 4.0.0.beta, < 5.0)
|
||||
=======
|
||||
sass-rails (3.2.6)
|
||||
railties (~> 3.2.0)
|
||||
>>>>>>> master
|
||||
sass (>= 3.1.10)
|
||||
sprockets-rails (~> 2.0.0.rc0)
|
||||
tilt (~> 1.3)
|
||||
selenium-webdriver (2.32.1)
|
||||
selenium-webdriver (2.33.0)
|
||||
childprocess (>= 0.2.5)
|
||||
multi_json (~> 1.0)
|
||||
rubyzip
|
||||
|
@ -172,7 +228,7 @@ GEM
|
|||
tolk (1.3.9)
|
||||
safe_yaml (~> 0.8)
|
||||
will_paginate
|
||||
treetop (1.4.12)
|
||||
treetop (1.4.14)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.37)
|
||||
|
|
|
@ -34,8 +34,9 @@ var TracksForm = {
|
|||
$('#default_project_name_id').val(name);
|
||||
$('#project_name').html(name);
|
||||
},
|
||||
set_tag_list: function (name) {
|
||||
set_tag_list_and_default_tag_list: function (name) {
|
||||
$('input#tag_list').val(name);
|
||||
$('input#initial_tag_list').val(name);
|
||||
},
|
||||
set_tag_list_for_multi_add: function (name) {
|
||||
$('#multi_tag_list').val(name);
|
||||
|
|
|
@ -21,6 +21,7 @@ class ApplicationController < ActionController::Base
|
|||
before_filter :set_time_zone
|
||||
before_filter :set_zindex_counter
|
||||
before_filter :set_locale
|
||||
append_before_filter :set_group_view_by
|
||||
prepend_before_filter :login_required
|
||||
prepend_before_filter :enable_mobile_content_negotiation
|
||||
after_filter :set_charset
|
||||
|
@ -291,4 +292,8 @@ class ApplicationController < ActionController::Base
|
|||
render :template => 'todos/done'
|
||||
end
|
||||
|
||||
def set_group_view_by
|
||||
@group_view_by = params['_group_view_by'] || cookies['group_view_by'] || 'context'
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -42,6 +42,7 @@ class ContextsController < ApplicationController
|
|||
@max_completed = current_user.prefs.show_number_completed
|
||||
@done = @context.todos.completed.limit(@max_completed).reorder("todos.completed_at DESC, todos.created_at DESC").includes(Todo::DEFAULT_INCLUDES)
|
||||
@not_done_todos = @context.todos.active.reorder("todos.due IS NULL, todos.due ASC, todos.created_at ASC").includes(Todo::DEFAULT_INCLUDES)
|
||||
@todos_without_project = @not_done_todos.select{|t| t.project.nil?}
|
||||
|
||||
@deferred_todos = @context.todos.deferred.includes(Todo::DEFAULT_INCLUDES)
|
||||
@pending_todos = @context.todos.pending.includes(Todo::DEFAULT_INCLUDES)
|
||||
|
@ -49,6 +50,9 @@ class ContextsController < ApplicationController
|
|||
@projects = current_user.projects
|
||||
@contexts = current_user.contexts
|
||||
|
||||
@projects_to_show = @projects.active
|
||||
@contexts_to_show = [@context]
|
||||
|
||||
@count = @not_done_todos.count + @deferred_todos.count + @pending_todos.count
|
||||
@page_title = "TRACKS::Context: #{@context.name}"
|
||||
respond_to do |format|
|
||||
|
|
|
@ -47,29 +47,6 @@ class LoginController < ApplicationController
|
|||
logout_user
|
||||
end
|
||||
|
||||
def expire_session
|
||||
# this is a hack to enable cucumber to expire a session by calling this
|
||||
# method. The method will be unavailable for production environment
|
||||
|
||||
@user.forget_me if logged_in?
|
||||
cookies.delete :auth_token
|
||||
session['user_id'] = nil
|
||||
reset_session
|
||||
|
||||
unless Rails.env.production?
|
||||
session['expiry_time'] = Time.now
|
||||
respond_to do |format|
|
||||
format.html { render :text => "Session expired for test purposes"}
|
||||
format.js { render :text => "" }
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
format.html { render :text => "Not available for production use"}
|
||||
format.js { render :text => "" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_expiry
|
||||
# Gets called by periodically_call_remote to check whether
|
||||
# the session has timed out yet
|
||||
|
|
|
@ -131,12 +131,14 @@ class ProjectsController < ApplicationController
|
|||
@not_done_todos = @project.todos.active_or_hidden.includes(Todo::DEFAULT_INCLUDES)
|
||||
@deferred_todos = @project.todos.deferred.includes(Todo::DEFAULT_INCLUDES)
|
||||
@pending_todos = @project.todos.pending.includes(Todo::DEFAULT_INCLUDES)
|
||||
@contexts_to_show = current_user.contexts.active
|
||||
@projects_to_show = [@project]
|
||||
|
||||
@done = {}
|
||||
@done = @project.todos.completed.
|
||||
reorder("todos.completed_at DESC").
|
||||
limit(current_user.prefs.show_number_completed).
|
||||
includes(Todo::DEFAULT_INCLUDES) unless current_user.prefs.show_number_completed == 0
|
||||
includes(Todo::DEFAULT_INCLUDES) unless @max_completed == 0
|
||||
|
||||
@count = @not_done_todos.size
|
||||
@down_count = @count + @deferred_todos.size + @pending_todos.size
|
||||
|
|
|
@ -3,7 +3,6 @@ class TodosController < ApplicationController
|
|||
skip_before_filter :login_required, :only => [:index, :tag]
|
||||
prepend_before_filter :login_or_feed_token_required, :only => [:index, :tag]
|
||||
append_before_filter :find_and_activate_ready, :only => [:index, :list_deferred]
|
||||
append_before_filter :set_group_view_by, :only => [:index, :tag, :create, :list_deferred, :destroy, :defer, :update, :toggle_check]
|
||||
|
||||
protect_from_forgery :except => :check_deferred
|
||||
|
||||
|
@ -595,12 +594,7 @@ class TodosController < ApplicationController
|
|||
@page_title = t('todos.tagged_page_title', :tag_name => @tag_title)
|
||||
@source_view = params['_source_view'] || 'tag'
|
||||
|
||||
if mobile?
|
||||
# mobile tags are routed with :name ending on .m. So we need to chomp it
|
||||
@tag_name = @tag_name.chomp('.m')
|
||||
else
|
||||
init_data_for_sidebar
|
||||
end
|
||||
init_data_for_sidebar unless mobile?
|
||||
|
||||
todos_with_tag_ids = find_todos_with_tag_expr(@tag_expr)
|
||||
|
||||
|
@ -833,8 +827,9 @@ class TodosController < ApplicationController
|
|||
end
|
||||
|
||||
def get_params_for_tag_view
|
||||
# use sanitize to prevent XSS attacks
|
||||
filter_format_for_tag_view
|
||||
|
||||
# use sanitize to prevent XSS attacks
|
||||
@tag_expr = []
|
||||
@tag_expr << sanitize(params[:name]).split(',')
|
||||
@tag_expr << sanitize(params[:and]).split(',') if params[:and]
|
||||
|
@ -850,6 +845,27 @@ class TodosController < ApplicationController
|
|||
@tag_title = @single_tag ? @tag_name : tag_title(@tag_expr)
|
||||
end
|
||||
|
||||
def filter_format_for_tag_view
|
||||
# routes for tag view do not set :format
|
||||
if params[:name] =~ /.*\.m$/
|
||||
set_format_for_tag_view(:m)
|
||||
elsif params[:name] =~ /.*\.txt$/
|
||||
set_format_for_tag_view(:txt)
|
||||
# set content-type to text/plain or it remains text/html
|
||||
response.headers["Content-Type"] = 'text/plain'
|
||||
elsif params[:format].nil?
|
||||
# if no format is given, default to html
|
||||
# note that if url has ?format=m, we should not overwrite it here
|
||||
request.format, params[:format] = :html, :html
|
||||
end
|
||||
end
|
||||
|
||||
def set_format_for_tag_view(format)
|
||||
# tag name ends with .m, set format to :m en remove .m from name
|
||||
request.format, params[:format] = format, format
|
||||
params[:name] = params[:name].chomp(".#{format.to_s}")
|
||||
end
|
||||
|
||||
def get_ids_from_tag_expr(tag_expr)
|
||||
ids = []
|
||||
tag_expr.each do |tag_list|
|
||||
|
|
|
@ -21,13 +21,13 @@ module TodosHelper
|
|||
end
|
||||
end
|
||||
|
||||
def show_grouped_todos
|
||||
def show_grouped_todos(settings = {})
|
||||
collection = (@group_view_by == 'context') ? @contexts_to_show : @projects_to_show
|
||||
render(:partial => collection, :locals => { :settings => {
|
||||
render(:partial => collection, :locals => { :settings => settings.reverse_merge!({
|
||||
:collapsible => true,
|
||||
:show_empty_containers => @show_empty_containers,
|
||||
:parent_container_type => @group_view_by
|
||||
}})
|
||||
})})
|
||||
end
|
||||
|
||||
def default_collection_settings
|
||||
|
@ -80,14 +80,14 @@ module TodosHelper
|
|||
:locals => {:settings => settings.reverse_merge!(default_collection_settings)}
|
||||
end
|
||||
|
||||
def show_todos_without_project(todos_without_project)
|
||||
def show_todos_without_project(todos_without_project, settings = {})
|
||||
render :partial => 'todos/collection',
|
||||
:object => todos_without_project,
|
||||
:locals => {:settings => {
|
||||
:locals => {:settings => settings.reverse_merge!({
|
||||
:collapsible => true,
|
||||
:container_name => "without_project",
|
||||
:parent_container_type => "home"
|
||||
}
|
||||
})
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -480,7 +480,7 @@ module TodosHelper
|
|||
def should_show_new_item(todo = @todo)
|
||||
return false if todo.nil?
|
||||
source_view do |page|
|
||||
page.todo { return !todo.hidden? }
|
||||
page.todo { return !todo.hidden? && !todo.deferred? }
|
||||
page.deferred { return todo.deferred? || todo.pending? }
|
||||
page.context { return show_todo_on_current_context_page && todo_should_not_be_hidden_on_context_page }
|
||||
page.tag { return todo.has_tag?(@tag_name) }
|
||||
|
@ -512,18 +512,18 @@ module TodosHelper
|
|||
end
|
||||
|
||||
def update_needs_to_hide_container
|
||||
if source_view_is(:tag)
|
||||
if source_view_is_one_of(:tag, :context, :project)
|
||||
return @remaining_in_context == 0 && (
|
||||
todo_moved_out_of_container ||
|
||||
(@todo_hidden_state_changed && @todo.hidden?) ||
|
||||
@todo_was_deferred_from_active_state ||
|
||||
@tag_was_removed ||
|
||||
@todo_was_destroyed ||
|
||||
(@todo.completed? && !(@original_item_was_deferred || @original_item_was_hidden))
|
||||
(@todo.completed? && !(@original_item_was_deferred || @original_item_was_hidden || @original_item_was_pending))
|
||||
)
|
||||
end
|
||||
|
||||
return false if source_view_is_one_of(:project, :calendar, :done, :context)
|
||||
return false if source_view_is_one_of(:calendar, :done)
|
||||
|
||||
return @remaining_in_context == 0
|
||||
end
|
||||
|
@ -599,7 +599,7 @@ module TodosHelper
|
|||
end
|
||||
|
||||
def todo_container_empty_id(todo)
|
||||
raise Exception.new, "no todo set in TodosHelper::todo_container_empty_id. You probably not assign @original_item" if !todo
|
||||
raise Exception.new, "no todo set in TodosHelper::todo_container_empty_id. You probably did not assign @original_item" if !todo
|
||||
@group_view_by == "project" ? project_container_empty_id(todo) : context_container_empty_id(todo)
|
||||
end
|
||||
|
||||
|
@ -609,8 +609,7 @@ module TodosHelper
|
|||
return "#{@new_due_id}_container" if source_view_is :calendar
|
||||
return "deferred_pending_container" if !source_view_is(:todo) && (todo.deferred? || todo.pending?)
|
||||
return "completed_container" if todo.completed?
|
||||
return "p#{todo.project_id}" if source_view_is :project
|
||||
return project_container_id(todo) if source_view_is_one_of(:todo, :tag) && @group_view_by == 'project'
|
||||
return project_container_id(todo) if source_view_is_one_of(:todo, :tag, :project, :context) && @group_view_by == 'project'
|
||||
return context_container_id(todo)
|
||||
end
|
||||
|
||||
|
@ -620,7 +619,7 @@ module TodosHelper
|
|||
source_view do |page|
|
||||
page.project {
|
||||
return "deferred_pending_container-empty-d" if empty_criteria_met
|
||||
return project_container_empty_id(todo)
|
||||
return todo_container_empty_id(todo)
|
||||
}
|
||||
page.tag {
|
||||
return "deferred_pending_container-empty-d" if empty_criteria_met
|
||||
|
@ -633,7 +632,7 @@ module TodosHelper
|
|||
}
|
||||
page.context {
|
||||
return "deferred_pending_container-empty-d" if empty_criteria_met
|
||||
return context_container_empty_id(todo)
|
||||
return todo_container_empty_id(todo)
|
||||
}
|
||||
page.todo {
|
||||
return todo_container_empty_id(todo)
|
||||
|
|
|
@ -539,14 +539,13 @@ class RecurringTodo < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def get_monthly_date(previous)
|
||||
|
||||
start = determine_start(previous)
|
||||
day = self.every_other1
|
||||
n = self.every_other2
|
||||
|
||||
case self.recurrence_selector
|
||||
when 0 # specific day of the month
|
||||
if start.mday >= day
|
||||
if start.mday > day
|
||||
# there is no next day n in this month, search in next month
|
||||
#
|
||||
# start += n.months
|
||||
|
|
|
@ -99,7 +99,7 @@ class Todo < ActiveRecord::Base
|
|||
end
|
||||
|
||||
event :block do
|
||||
transitions :to => :pending, :from => [:active, :deferred]
|
||||
transitions :to => :pending, :from => [:active, :deferred, :project_hidden]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -152,6 +152,14 @@ class Todo < ActiveRecord::Base
|
|||
return !( uncompleted_predecessors.empty? || state == 'project_hidden' )
|
||||
end
|
||||
|
||||
def guard_for_transition_from_deferred_to_pending
|
||||
no_uncompleted_predecessors? && not_part_of_hidden_container?
|
||||
end
|
||||
|
||||
def not_part_of_hidden_container?
|
||||
!( (self.project && self.project.hidden?) || self.context.hidden? )
|
||||
end
|
||||
|
||||
# Returns a string with description <context, project>
|
||||
def specification
|
||||
project_name = self.project.is_a?(NullProject) ? "(none)" : self.project.name
|
||||
|
@ -195,7 +203,7 @@ class Todo < ActiveRecord::Base
|
|||
def remove_predecessor(predecessor)
|
||||
self.predecessors.delete(predecessor)
|
||||
if self.predecessors.empty?
|
||||
self.activate!
|
||||
self.not_part_of_hidden_container? ? self.activate! : self.hide!
|
||||
else
|
||||
save!
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# invalidate the cache every day because of staleness or
|
||||
# rendering of "due in x days" that change without touching updated at of the todo
|
||||
cache [context, @source_view, current_user.date.strftime("%Y%m%d"), @tag_name] do
|
||||
%>
|
||||
-%>
|
||||
<%=
|
||||
render :partial => 'todos/collection',
|
||||
:object => @not_done,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="list-stategroup-contexts-container" id="list-<%= state %>-contexts-container">
|
||||
<h2>
|
||||
<span id="<%= state %>-contexts-count" class="badge"><%= context_state_group.length %></span>
|
||||
<%= t("states."+ state +"_plural")%> <%= t('common.contexts') %>
|
||||
<%= t("states.contexts."+ state) %>
|
||||
</h2>
|
||||
|
||||
<div id="<%= state%>-contexts-empty-nd" style="<%= no_contexts ? 'display:block' : 'display:none'%>">
|
||||
|
|
|
@ -2,9 +2,17 @@
|
|||
suffix_completed = t('contexts.last_completed_in_context', :number=>prefs.show_number_completed)
|
||||
deferred_pending_options = {:append_descriptor => nil, :parent_container_type => 'context'}
|
||||
done_todo_options = {:append_descriptor => suffix_completed, :suppress_context => true, :parent_container_type => 'context'}
|
||||
show_empty_containers = (@group_view_by == 'context')
|
||||
-%>
|
||||
<div id="display_box">
|
||||
<%= render :partial => @context, :locals => { :settings => {:collapsible => false, :show_empty_containers => true, :parent_container_type => 'context' }} %>
|
||||
|
||||
<%= empty_message_holder("not_done_project", @not_done_todos.empty?) %>
|
||||
|
||||
<%= show_grouped_todos({:collapsible => false, :show_empty_containers => show_empty_containers, :parent_container_type => 'context'}) %>
|
||||
|
||||
<% if @group_view_by == 'project' -%>
|
||||
<%= show_todos_without_project(@todos_without_project, {:collapsible => false, :parent_container_type => 'context', :title_param => @context.name}) -%>
|
||||
<% end -%>
|
||||
|
||||
<%= show_deferred_pending_todos(@deferred_todos, @pending_todos, deferred_pending_options) %>
|
||||
|
||||
|
|
|
@ -46,10 +46,6 @@
|
|||
</h1>
|
||||
</div>
|
||||
<div id="minilinks">
|
||||
<%= link_to(t('layouts.toggle_contexts'), "#", {:title => t('layouts.toggle_contexts_title'), :id => "toggle-contexts-nav"}) %>
|
||||
|
|
||||
<%= link_to(t('layouts.toggle_notes'), "#", {:accesskey => "S", :title => t('layouts.toggle_notes_title'), :id => "toggle-notes-nav"}) %>
|
||||
|
|
||||
<%= link_to("#{t('common.logout')} (#{current_user.display_name}) »".html_safe, logout_path) %>
|
||||
</div>
|
||||
<div id="navcontainer">
|
||||
|
@ -66,13 +62,15 @@
|
|||
<li><%= navigation_link( t('layouts.navigation.recurring_todos'), {:controller => "recurring_todos", :action => "index"}, :title => t('layouts.navigation.recurring_todos_title')) %></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#"><%= t('layouts.navigation.view') %></a>
|
||||
<li id="menu_view"><a href="#" id="menu_view_link"><%= t('layouts.navigation.view') %></a>
|
||||
<ul>
|
||||
<li><%= navigation_link( t('layouts.navigation.calendar'), calendar_path, :title => t('layouts.navigation.calendar_title')) %></li>
|
||||
<li><%= navigation_link( t('layouts.navigation.completed_tasks'), done_overview_path, {:accesskey=>"d", :title=>t('layouts.navigation.completed_tasks_title')} ) %></li>
|
||||
<li><%= navigation_link( t('layouts.navigation.feeds'), feeds_path, :title => t('layouts.navigation.feeds_title')) %></li>
|
||||
<li><%= navigation_link( t('layouts.navigation.stats'), stats_path, :title => t('layouts.navigation.stats_title')) %></li>
|
||||
<li><hr/></li>
|
||||
<li id="menu_view_toggle_contexts"><%= link_to(t('layouts.toggle_contexts'), "#", {:title => t('layouts.toggle_contexts_title'), :id => "toggle-contexts-nav"}) %></li>
|
||||
<li><%= link_to(t('layouts.toggle_notes'), "#", {:accesskey => "S", :title => t('layouts.toggle_notes_title'), :id => "toggle-notes-nav"}) %></li>
|
||||
<%= group_view_by_menu_entry %>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
|
@ -2,11 +2,8 @@
|
|||
@not_done = @not_done_todos.select {|t| t.project_id == project.id }
|
||||
# invalidate the cache every day because of staleness or
|
||||
# rendering of "due in x days" that change without touching updated at of the todo
|
||||
cache [project, @source_view, current_user.date.strftime("%Y%m%d")] do
|
||||
cache [project, @source_view, current_user.date.strftime("%Y%m%d"), @tag_name] do
|
||||
-%>
|
||||
<% if source_view_is :project -%>
|
||||
<%= render :partial => "project_settings_container", :locals => {:project => project} %>
|
||||
<% end -%>
|
||||
<%=
|
||||
title = source_view_is(:project) ? t('projects.actions_in_project_title') : show_project_name(project)
|
||||
|
||||
|
|
|
@ -8,14 +8,9 @@
|
|||
<h2>
|
||||
<span id="<%= state %>-projects-count" class="badge"><%= project_state_group.length%><%= total_count_string%></span>
|
||||
|
||||
<%= t('common.last' ) unless ( ['review','stalled','blocked','current'].include?(state) )%>
|
||||
<% if (I18n.locale == :fr) %>
|
||||
<%= t('common.projects').downcase %>
|
||||
<%= t('states.'+state+'_plural' ).downcase %><%= total_count==-1 ? "" : " (#{link_to(t('common.show_all'), done_projects_path)})".html_safe%>
|
||||
<% else %>
|
||||
<%= t('states.'+state+'_plural' )%>
|
||||
<%= t('common.projects') %><%= total_count==-1 ? "" : " (#{link_to(t('common.show_all'), done_projects_path)})".html_safe%>
|
||||
<% end %>
|
||||
<%= t('common.last' ) if state == 'completed' %>
|
||||
<%= t('states.projects.'+state) %>
|
||||
<%= total_count==-1 ? "" : " (#{link_to(t('common.show_all'), done_projects_path)})".html_safe%>
|
||||
|
||||
</h2>
|
||||
<% unless suppress_sort_menu %>
|
||||
|
|
|
@ -5,11 +5,19 @@
|
|||
:suppress_project => true,
|
||||
:parent_container_type => 'project'
|
||||
}
|
||||
if @not_done_todos.count == 0
|
||||
# force project view so one empty container will be shown with an empty message
|
||||
@group_view_by = 'project'
|
||||
end
|
||||
-%>
|
||||
<div id="display_box">
|
||||
<%= project_next_prev %>
|
||||
|
||||
<%= render :partial => @project, :locals => {:settings => {:collapsible => false, :show_empty_containers => true, :parent_container_type => 'project' }} %>
|
||||
<%= render :partial => "project_settings_container", :locals => {:project => @project} %>
|
||||
|
||||
<%= empty_message_holder("not_done_context", @not_done_todos.empty?) %>
|
||||
|
||||
<%= show_grouped_todos({:collapsible => false, :show_empty_containers => false, :parent_container_type => 'project' }) %>
|
||||
|
||||
<%= show_deferred_pending_todos(@deferred_todos, @pending_todos, deferred_pending_options) %>
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ function update_project_page() {
|
|||
TracksForm.set_context_name_and_default_context_name("<%= escape_javascript(@project.default_context.name)%>");
|
||||
<% end %>
|
||||
<% if @project.default_tags %>
|
||||
TracksForm.set_tag_list("<%= escape_javascript(@project.default_tags)%>");
|
||||
TracksForm.set_tag_list_and_default_tag_list("<%= escape_javascript(@project.default_tags)%>");
|
||||
<% end %>
|
||||
TracksPages.update_sidebar(html_for_sidebar());
|
||||
}
|
||||
|
|
|
@ -84,12 +84,12 @@
|
|||
:month => select_tag('recurring_todo[yearly_month_of_year2]', options_for_select(@months_of_year, @recurring_todo.yearly_month_of_year2))) %><br/>
|
||||
</div>
|
||||
<div id="recurring_target">
|
||||
<label><%= t('todos.recurrence.recurrence_on_options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'due_date', @recurring_todo.target == 'due_date')%> <%= t('todos.recurrence.recurrence_on_due_date') %>. <%= t('todos.recurrence.show_options') %>:
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '1', @recurring_todo.show_always?)%> <%= t('todos.recurrence.show_option_always') %>
|
||||
<label><%= t('todos.recurrence.recurrence_on.options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'due_date', @recurring_todo.target == 'due_date')%> <%= t('todos.recurrence.recurrence_on.due_date') %>. <%= t('todos.recurrence.recurrence_on.show_options') %>:
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '1', @recurring_todo.show_always?)%> <%= t('todos.recurrence.recurrence_on.show_always') %>
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '0', !@recurring_todo.show_always?)%>
|
||||
<%= raw t('todos.recurrence.show_days_before', :days => text_field_tag( 'recurring_todo[recurring_show_days_before]', @recurring_todo.show_from_delta, {"size" => 3})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'show_from_date', @recurring_todo.target == 'show_from_date')%> <%= t('todos.recurrence.from_tickler') %><br/>
|
||||
<%= raw t('todos.recurrence.recurrence_on.show_days_before', :days => text_field_tag( 'recurring_todo[recurring_show_days_before]', @recurring_todo.show_from_delta, {"size" => 3})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'show_from_date', @recurring_todo.target == 'show_from_date')%> <%= t('todos.recurrence.recurrence_on.from_tickler') %><br/>
|
||||
<br/>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -76,13 +76,13 @@
|
|||
:month => select_tag('recurring_todo[yearly_month_of_year2]', options_for_select(@months_of_year, Time.zone.now.month))) %><br/>
|
||||
</div>
|
||||
<div id="recurring_target">
|
||||
<label><%= t('todos.recurrence.recurrence_on_options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'due_date', true)%> <%= t('todos.recurrence.recurrence_on_due_date') %>. <%= t('todos.recurrence.show_options') %>:
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '1', true)%> <%= t('todos.recurrence.show_option_always') %>
|
||||
<label><%= t('todos.recurrence.recurrence_on.options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'due_date', true)%> <%= t('todos.recurrence.recurrence_on.due_date') %>. <%= t('todos.recurrence.recurrence_on.show_options') %>:
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '1', true)%> <%= t('todos.recurrence.recurrence_on.show_always') %>
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '0', false)%>
|
||||
<%= raw t('todos.recurrence.show_days_before', :days => text_field_tag( 'recurring_todo[recurring_show_days_before]', "0", {"size" => 3})) %>
|
||||
<%= raw t('todos.recurrence.recurrence_on.show_days_before', :days => text_field_tag( 'recurring_todo[recurring_show_days_before]', "0", {"size" => 3})) %>
|
||||
<br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'show_from_date', false)%> <%= t('todos.recurrence.from_tickler') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'show_from_date', false)%> <%= t('todos.recurrence.recurrence_on.from_tickler') %><br/>
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
$('#todo-form-new-action').clearDeps();
|
||||
TracksForm.set_context_name('<%=escape_javascript @initial_context_name%>');
|
||||
TracksForm.set_project_name('<%=escape_javascript @initial_project_name%>');
|
||||
TracksForm.set_tag_list('<%=escape_javascript @initial_tags%>');
|
||||
TracksForm.set_tag_list_and_default_tag_list('<%=escape_javascript @initial_tags%>');
|
||||
$('#todo-form-new-action input:text:first').focus();
|
||||
$('#new_todo_starred_link .todo_star').removeClass('starred');
|
||||
$('#new_todo_starred').val('false');
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
animation << "add_todo_to_container" unless source_view_is(:done)
|
||||
animation << "block_predecessors"
|
||||
end
|
||||
animation << "update_empty_container" if source_view_is_one_of(:tag, :todo, :deferred)
|
||||
animation << "update_empty_container" if source_view_is_one_of(:tag, :todo, :deferred, :project, :context)
|
||||
animation << "regenerate_predecessor_family"
|
||||
else
|
||||
animation << "replace_todo"
|
||||
|
@ -63,7 +63,6 @@ function replace_todo(next_steps) {
|
|||
}
|
||||
|
||||
function add_todo_to_container(next_steps) {
|
||||
// <%= @group_view_by %>
|
||||
$('#<%= item_container_id(@todo) %>_items').append(html_for_todo());
|
||||
<% if should_make_context_visible -%>
|
||||
$('#<%= item_container_id(@todo) %>').slideDown(500, function() {
|
||||
|
@ -120,7 +119,7 @@ function highlight_updated_todo(next_steps) {
|
|||
|
||||
function activate_pending_todos(next_steps) {
|
||||
<% # Activate pending todos that are successors of the completed
|
||||
if @saved && @pending_to_activate
|
||||
if @pending_to_activate
|
||||
# do not render the js in case of an error or if no todos to activate
|
||||
@pending_to_activate.each do |t|
|
||||
html = escape_javascript(render(:partial => t, :locals => { :parent_container_type => parent_container_type }))
|
||||
|
@ -173,7 +172,7 @@ end
|
|||
|
||||
function html_for_recurring_todo() {
|
||||
<%-
|
||||
js = @saved && @new_recurring_todo ? escape_javascript(render(:partial => @new_recurring_todo, :locals => { :parent_container_type => parent_container_type })) : ""
|
||||
js = @new_recurring_todo ? escape_javascript(render(:partial => @new_recurring_todo, :locals => { :parent_container_type => parent_container_type })) : ""
|
||||
-%>
|
||||
return "<%= js %>";
|
||||
}
|
||||
|
@ -181,7 +180,7 @@ function html_for_recurring_todo() {
|
|||
function html_for_todo() {
|
||||
<%-
|
||||
js = ""
|
||||
if @saved && !source_view_is(:done)
|
||||
if !source_view_is(:done)
|
||||
js = escape_javascript(render(
|
||||
:partial => @todo,
|
||||
:locals => {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
end
|
||||
animation << "hide_container" if update_needs_to_hide_container
|
||||
animation << "highlight_updated_todo"
|
||||
animation << "update_empty_container" if source_view_is_one_of(:tag, :todo, :deferred)
|
||||
animation << "update_empty_container" if source_view_is_one_of(:tag, :todo, :deferred, :project, :context)
|
||||
animation << "update_predecessors"
|
||||
%>
|
||||
TracksPages.page_notify('notice', '<%=escape_javascript @status_message%>', 5);
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -333,6 +333,14 @@ en:
|
|||
hide_action_form_title: Hide new action form
|
||||
make_actions_dependent: Make actions dependent on each other
|
||||
states:
|
||||
contexts:
|
||||
hidden: Hidden contexts
|
||||
active: Active contexts
|
||||
closed: Closed contexts
|
||||
projects:
|
||||
hidden: Hidden projects
|
||||
active: Active projects
|
||||
closed: Closed projects
|
||||
hidden_plural: Hidden
|
||||
completed: Completed
|
||||
completed_plural: Completed
|
||||
|
@ -427,6 +435,8 @@ en:
|
|||
completed: Currently there are no completed actions
|
||||
title: No actions found
|
||||
not_done_with_tag: "Currently there are no incomplete actions with the tag '%{param}'"
|
||||
not_done_project: Currently there are no incomplete actions in this project
|
||||
not_done_context: Currently there are no incomplete actions in this context
|
||||
completed_recurring: Currently there are no completed recurring todos
|
||||
not_done: Currently there are no incomplete actions
|
||||
project: Currently there are no incomplete actions in this project
|
||||
|
@ -444,6 +454,7 @@ en:
|
|||
home_completed: Completed actions
|
||||
tag_completed: "Completed actions tagged with '%{param}'"
|
||||
home_without_project: "Actions without project"
|
||||
context_without_project: "Actions without project in %{param}"
|
||||
project_project: "Actions in this project"
|
||||
project_deferred_pending: Deferred/pending actions in this project
|
||||
context_deferred_pending: Deferred/pending actions in this context
|
||||
|
@ -584,7 +595,6 @@ en:
|
|||
ends_on_number_times: Ends after %{number} times
|
||||
ends_on_date: Ends on %{date}
|
||||
every_work_day: Every work day
|
||||
recurrence_on_due_date: the date that the todo is due
|
||||
weekly_options: Settings for weekly recurring actions
|
||||
weekly: Weekly
|
||||
monthly_options: Settings for monthly recurring actions
|
||||
|
@ -633,16 +643,18 @@ en:
|
|||
due: due
|
||||
until: until
|
||||
every_month: every month
|
||||
show_option_always: always
|
||||
daily: Daily
|
||||
yearly_every_x_day: Every %{month} %{day}
|
||||
recurrence_on_options: Set recurrence on
|
||||
recurrence_on:
|
||||
options: Use the calculated date to
|
||||
due_date: set the actions due date
|
||||
show_options: Show the action
|
||||
show_always: always
|
||||
show_days_before: "not until %{days} days before the due date"
|
||||
from_tickler: set the date the action should be shown (do not set a due date)
|
||||
daily_every_number_day: Every %{number} day(s)
|
||||
show_options: Show the todo
|
||||
weekly_every_number_week: Returns every %{number} week on
|
||||
ends_on: Ends on
|
||||
show_days_before: "%{days} days before the todo is due"
|
||||
from_tickler: the date todo comes from tickler (no due date set)
|
||||
no_end_date: No end date
|
||||
day_x_on_every_x_month: Day %{day} on every %{month} month
|
||||
yearly_options: Settings for yearly recurring actions
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -5,7 +5,6 @@ Tracksapp::Application.routes.draw do
|
|||
|
||||
post 'login' => 'login#login'
|
||||
get 'login' => 'login#login'
|
||||
get 'login/expire_session' => 'login#expire_session'
|
||||
get 'login/check_expiry' => 'login#check_expiry'
|
||||
get 'logout' => 'login#logout'
|
||||
|
||||
|
@ -102,9 +101,13 @@ Tracksapp::Application.routes.draw do
|
|||
post 'add_predecessor'
|
||||
end
|
||||
end
|
||||
get 'todos/tag/:name' => 'todos#tag', :as => :tag
|
||||
get 'tags.autocomplete' => "todos#tags", :format => 'autocomplete'
|
||||
|
||||
# match /todos/tag and put everything in :name, including extensions like .m and .txt.
|
||||
# This means the controller action needs to parse the extension and set format/content type
|
||||
# Needed for /todos/tag/first.last.m to work
|
||||
get 'todos/tag/:name' => 'todos#tag', :as => :tag, :format => false, :name => /.*/
|
||||
|
||||
get 'tags.autocomplete' => "todos#tags", :format => 'autocomplete'
|
||||
get 'todos/done/tag/:name' => "todos#done_tag", :as => :done_tag
|
||||
get 'todos/all_done/tag/:name' => "todos#all_done_tag", :as => :all_done_tag
|
||||
get 'auto_complete_for_predecessor' => 'todos#auto_complete_for_predecessor'
|
||||
|
|
|
@ -16,10 +16,23 @@
|
|||
== Version 2.3devel
|
||||
|
||||
New and changed features
|
||||
* you can select to group todos on the home page by context or by
|
||||
project (using the view menu). This also works for tag page
|
||||
* You can select to group todos on the home page by context or by
|
||||
project (using the view menu). This also works for tag page, the project page,
|
||||
the tickler and the context page
|
||||
* You can now change the state of a context to closed
|
||||
* Czech locale has been renamed from cz to cs to follow ISO standards
|
||||
* The toggle-notes and toggle-collapsed-containers have been moved into the view
|
||||
menu
|
||||
* Bugfixes
|
||||
* Tracks is tested on Ruby 1.9.3 and on Ruby 2.0
|
||||
|
||||
Removed features
|
||||
* This version of Tracks dropped support for Ruby 1.8.x. Please use Ruby 1.9 or
|
||||
Ruby 2.0
|
||||
|
||||
Under the hood
|
||||
* Upgrade to Rails 3.213
|
||||
* Several refactorings al over the place for easier maintenance
|
||||
|
||||
== Version 2.2.2
|
||||
|
||||
|
|
|
@ -68,10 +68,10 @@ Feature: dependencies
|
|||
And "test 2" depends on "test 1"
|
||||
When I go to the "dependencies" project
|
||||
Then I should see "test 2" in the deferred container
|
||||
And I should see "test 1" in the action container
|
||||
And I should see "test 1" in the context container for "@pc"
|
||||
When I mark "test 1" as complete
|
||||
Then I should see "test 1" in the completed container
|
||||
And I should see "test 2" in the action container
|
||||
And I should see "test 2" in the context container for "@pc"
|
||||
And I should not see "test 2" in the deferred container
|
||||
And I should see empty message for deferred todos of project
|
||||
|
||||
|
@ -86,9 +86,9 @@ Feature: dependencies
|
|||
And "test 2" depends on "test 1"
|
||||
When I go to the "dependencies" project
|
||||
Then I should see "test 2" in the deferred container
|
||||
And I should see "test 1" in the action container
|
||||
And I should see "test 1" in the context container for "@pc"
|
||||
When I delete the action "test 1"
|
||||
Then I should see "test 2" in the action container
|
||||
Then I should see "test 2" in the context container for "@pc"
|
||||
And I should not see "test 2" in the deferred container
|
||||
And I should see empty message for deferred todos of project
|
||||
|
||||
|
@ -122,7 +122,7 @@ Feature: dependencies
|
|||
When I go to the "dependencies" project
|
||||
And I drag "test 1" to "test 3"
|
||||
Then I should see an error flash message saying "Cannot add this action as a dependency to a completed action!"
|
||||
And I should see "test 1" in the project container of "dependencies"
|
||||
And I should see "test 1" in the context container for "@pc"
|
||||
|
||||
@javascript
|
||||
Scenario Outline: Marking a successor as complete will update predecessor
|
||||
|
@ -171,5 +171,6 @@ Feature: dependencies
|
|||
Scenarios:
|
||||
| page | grouping |
|
||||
| "dependencies" project | project |
|
||||
| "dependencies" project | context |
|
||||
| tag page for "bla" | context |
|
||||
| tag page for "bla" | project |
|
|
@ -55,7 +55,7 @@ Feature: Edit a next action from every page
|
|||
@javascript @wip
|
||||
Scenario Outline: Changing container of the todo in that container will hide it
|
||||
# this script fails on https://code.google.com/p/selenium/issues/detail?id=3075 for selenium-webdriver > 2.14.
|
||||
# and selenium-webdriver < 2.20 fails on firefox 11 :-( So @wip for now. This may work on webkit though
|
||||
# and selenium-webdriver < 2.20 fails on firefox 11 :-( So @wip for now. This may work with webkit though
|
||||
Given I have a todo "delete me" in the context "@home" in the project "do it"
|
||||
And I have a project "go for it"
|
||||
And I have selected the view for group by <grouping>
|
||||
|
@ -77,6 +77,7 @@ Feature: Edit a next action from every page
|
|||
@javascript
|
||||
Scenario Outline: Deleting the last todo in container will show empty message # only project, context, tag, not todo
|
||||
Given I have a context called "@home"
|
||||
And I have selected the view for group by <grouping>
|
||||
And I have a project "my project" that has the following todos
|
||||
| context | description | tags |
|
||||
| @home | first action | test, bla |
|
||||
|
@ -90,10 +91,13 @@ Feature: Edit a next action from every page
|
|||
Then I should see empty message for todos of <page type>
|
||||
|
||||
Scenarios:
|
||||
| page | page type |
|
||||
| "my project" project | project |
|
||||
| context page for "@home" | context |
|
||||
| tag page for "bla" | tag |
|
||||
| page | page type | grouping |
|
||||
| "my project" project | project | project |
|
||||
| "my project" project | project | context |
|
||||
| context page for "@home" | context | context |
|
||||
| context page for "@home" | context | project |
|
||||
| tag page for "bla" | tag | context |
|
||||
| tag page for "bla" | tag | project |
|
||||
|
||||
@javascript
|
||||
Scenario Outline: I can mark an active todo complete and it will update empty messages
|
||||
|
@ -156,7 +160,7 @@ Feature: Edit a next action from every page
|
|||
| home page | home | project | container for project "visible project" |
|
||||
|
||||
@javascript
|
||||
Scenario Outline: I can mark a completed todo active and it will update empty messages for pages without context containers
|
||||
Scenario Outline: I can mark a completed todo active and it will update empty messages for pages without hideable containers
|
||||
Given I have a completed todo with description "visible todo" in project "visible project" with tags "starred" in the context "visible context"
|
||||
When I go to the <page>
|
||||
Then I should see empty message for todos of <page type>
|
||||
|
|
|
@ -123,7 +123,7 @@ Feature: Edit a project
|
|||
Scenario: Moving the todo to the tickler will move todo to tickler container and update empty messages
|
||||
Given I have a project "test" with 1 todos
|
||||
When I go to the "test" project
|
||||
Then I should see "todo 1" in the action container
|
||||
Then I should see "todo 1" in the context container for "Context A"
|
||||
And I should see empty message for deferred todos of project
|
||||
And I should see empty message for completed todos of project
|
||||
When I defer "todo 1" for 1 day
|
||||
|
|
|
@ -97,7 +97,9 @@ Feature: Add new next action from every page
|
|||
| tickler page | context | not see |
|
||||
| tickler page | project | not see |
|
||||
| "test project" project | context | see |
|
||||
| "test project" project | project | see |
|
||||
| context page for "test context" | context | see |
|
||||
| context page for "test context" | project | see |
|
||||
| tag page for "starred" | context | see |
|
||||
| tag page for "starred" | project | see |
|
||||
|
||||
|
@ -124,7 +126,9 @@ Feature: Add new next action from every page
|
|||
| tickler page | not see | 0 | 3 | context |
|
||||
| tickler page | not see | 0 | 3 | project |
|
||||
| "testing" project | see | 3 | 3 | context |
|
||||
| "testing" project | see | 3 | 3 | project |
|
||||
| context page for "test context" | see | 2 | 3 | context |
|
||||
| context page for "test context" | see | 2 | 3 | project |
|
||||
| tag page for "starred" | see | 2 | 3 | context |
|
||||
| tag page for "starred" | see | 2 | 3 | project |
|
||||
|
||||
|
@ -199,9 +203,13 @@ Feature: Add new next action from every page
|
|||
| tickler page | context | not see | not see |
|
||||
| tickler page | project | not see | not see |
|
||||
| "visible project" project | project | not see | see |
|
||||
| "visible project" project | context | not see | see |
|
||||
| "hidden project" project | project | see | not see |
|
||||
| "hidden project" project | context | see | not see |
|
||||
| context page for "visible context" | context | not see | see |
|
||||
| context page for "visible context" | project | not see | see |
|
||||
| context page for "other context" | context | not see | not see |
|
||||
| context page for "other context" | project | not see | not see |
|
||||
| tag page for "starred" | context | not see | not see |
|
||||
| tag page for "starred" | project | not see | not see |
|
||||
| tag page for "test" | context | see | see |
|
||||
|
|
|
@ -11,8 +11,10 @@ When(/^I collapse the project container of "(.*?)"$/) do |project_name|
|
|||
end
|
||||
|
||||
When /^I toggle all collapsed context containers$/ do
|
||||
open_view_menu do
|
||||
click_link 'Toggle collapsed contexts'
|
||||
end
|
||||
end
|
||||
|
||||
####### Context #######
|
||||
|
||||
|
@ -91,7 +93,6 @@ Then(/^I should (not see|see) "([^"]*)" in the (completed|done today|done this w
|
|||
id = 'completed_rest_of_month_container' if container == 'done this month'
|
||||
|
||||
css = "div##{id} div#line_todo_#{find_todo(todo_description).id}"
|
||||
page.should have_css(css)
|
||||
check_css_visibility(visible, css)
|
||||
end
|
||||
|
||||
|
@ -138,9 +139,8 @@ end
|
|||
|
||||
Then /^I should (see|not see) empty message for (done today|done this week|done this month|completed todos|deferred todos|todos) (of done actions|of context|of project|of home|of tag)/ do |visible, state, type|
|
||||
css = "error: wrong state"
|
||||
css = "div#c#{@context.id}-empty-d" if state == "todos" && type == "of context"
|
||||
css = "div#p#{@project.id}-empty-d" if state == "todos" && type == "of project"
|
||||
css = "div#no_todos_in_view" if state == "todos" && (type == "of home" || type == "of tag")
|
||||
css = "div#c#{@context.id}-empty-d" if state == "todos"
|
||||
css = "div#no_todos_in_view" if state == "todos" && ["of home", "of tag", "of context", "of project"].include?(type)
|
||||
css = "div#completed_today_container" if state == "done today"
|
||||
css = "div#completed_rest_of_week_container" if state == "done this week"
|
||||
css = "div#completed_rest_of_month_container" if state == "done this month"
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
Given /^I have logged in as "(.*)" with password "(.*)"$/ do |username, password|
|
||||
step "I go to the login page"
|
||||
fill_in "user_login", :with => username
|
||||
fill_in "user_password", :with => password
|
||||
uncheck "user_noexpiry"
|
||||
click_button "Sign in"
|
||||
|
||||
logout_regexp = @mobile_interface ? "Logout" : "Logout \(#{username}\)"
|
||||
page.should have_content(logout_regexp)
|
||||
@current_user = User.where(:login => username).first
|
||||
user = User.where(:login => username).first
|
||||
request_signin_as(user)
|
||||
@current_user = user
|
||||
end
|
||||
|
||||
When /^I submit the login form as user "([^\"]*)" with password "([^\"]*)"$/ do |username, password|
|
||||
|
|
|
@ -30,7 +30,7 @@ When /^I edit the first note to "([^"]*)"$/ do |note_body|
|
|||
end
|
||||
end
|
||||
|
||||
When /^I toggle the note of "([^"]*)"$/ do |todo_description|
|
||||
When(/^I toggle the note of "([^"]*)"$/) do |todo_description|
|
||||
todo = @current_user.todos.where(:description => todo_description).first
|
||||
todo.should_not be_nil
|
||||
|
||||
|
@ -39,8 +39,10 @@ When /^I toggle the note of "([^"]*)"$/ do |todo_description|
|
|||
end
|
||||
|
||||
When /^I click Toggle Notes$/ do
|
||||
open_view_menu do
|
||||
click_link 'Toggle notes'
|
||||
end
|
||||
end
|
||||
|
||||
When /^I toggle all notes$/ do
|
||||
step "I click Toggle Notes"
|
||||
|
|
|
@ -70,9 +70,9 @@ Given /^I have ([0-9]+) todos$/ do |count|
|
|||
end
|
||||
|
||||
Given /^I have a todo with description "([^"]*)" in project "([^"]*)" with tags "([^"]*)" in the context "([^"]*)"$/ do |action_description, project_name, tags, context_name|
|
||||
context = @current_user.contexts.where(:name => context_name).first_or_create
|
||||
project = @current_user.projects.where(:name => project_name).first_or_create
|
||||
@todo = @current_user.todos.create!(:context_id => context.id, :project_id => project.id, :description => action_description)
|
||||
@context = @current_user.contexts.where(:name => context_name).first_or_create
|
||||
@project = @current_user.projects.where(:name => project_name).first_or_create
|
||||
@todo = @current_user.todos.create!(:context_id => @context.id, :project_id => @project.id, :description => action_description)
|
||||
@todo.tag_with(tags)
|
||||
@todo.save
|
||||
end
|
||||
|
|
52
features/support/tracks_login_helper.rb
Normal file
52
features/support/tracks_login_helper.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
class SessionBackdoorController < ::ApplicationController
|
||||
skip_before_filter :login_required
|
||||
|
||||
def create
|
||||
session['user_id'] = params[:user_id]
|
||||
user = User.find(params[:user_id])
|
||||
set_current_user(user)
|
||||
user.remember_me
|
||||
cookies[:auth_token] = { :value => user.remember_token, :expires => user.remember_token_expires_at }
|
||||
redirect_to root_path
|
||||
end
|
||||
|
||||
def expire_session
|
||||
current_user.forget_me if logged_in?
|
||||
cookies.delete :auth_token
|
||||
session['user_id'] = nil
|
||||
reset_session
|
||||
session['expiry_time'] = Time.now
|
||||
|
||||
respond_to do |format|
|
||||
format.html { render :text => "Session expired for test purposes"}
|
||||
format.js { render :text => "" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module TracksLoginHelper
|
||||
begin
|
||||
_routes = Rails.application.routes
|
||||
_routes.disable_clear_and_finalize = true
|
||||
_routes.clear!
|
||||
Rails.application.routes_reloader.paths.each{ |path| load(path) }
|
||||
_routes.draw do
|
||||
# here you can add any route you want
|
||||
match "/test_login_backdoor", to: "session_backdoor#create"
|
||||
match "login/expire_session", to: "session_backdoor#expire_session"
|
||||
end
|
||||
ActiveSupport.on_load(:action_controller) { _routes.finalize! }
|
||||
ensure
|
||||
_routes.disable_clear_and_finalize = false
|
||||
end
|
||||
|
||||
def request_signin_as(user)
|
||||
visit "/test_login_backdoor?user_id=#{user.id}"
|
||||
end
|
||||
|
||||
def signin_as(user)
|
||||
session[:user_id] = user.id
|
||||
@current_user = user
|
||||
end
|
||||
|
||||
end
|
|
@ -97,6 +97,23 @@ module TracksStepHelper
|
|||
execute_javascript("$('#{sortable_css}').simulateDragSortable({move: #{delta}, handle: '.grip'});")
|
||||
end
|
||||
|
||||
def open_view_menu
|
||||
view_menu = "ul.sf-menu li#menu_view"
|
||||
|
||||
# click menu
|
||||
view_menu_link = "#{view_menu} a#menu_view_link"
|
||||
page.should have_css(view_menu_link, :visible => true)
|
||||
page.find(view_menu_link).click
|
||||
|
||||
# wait for menu to be visible
|
||||
view_menu_item = "#{view_menu} li#menu_view_toggle_contexts"
|
||||
page.should have_css(view_menu_item)
|
||||
|
||||
within view_menu do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
def open_submenu_for(todo)
|
||||
submenu_arrow = "div#line_todo_#{todo.id} img.todo-submenu"
|
||||
page.should have_css(submenu_arrow, :visible=>true)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
World(TracksLoginHelper)
|
||||
World(TracksStepHelper)
|
||||
World(TracksFormHelper)
|
||||
World(TracksIdHelper)
|
|
@ -235,6 +235,52 @@ class RecurringTodosControllerTest < ActionController::TestCase
|
|||
assert_equal true, recurring_todo.show_always?
|
||||
end
|
||||
|
||||
def test_start_on_monthly_rec_todo
|
||||
Timecop.travel(Time.local(2012,1,1)) do
|
||||
|
||||
login_as(:admin_user)
|
||||
|
||||
put :create,
|
||||
"context_name"=>"library",
|
||||
"project_name"=>"Build a working time machine",
|
||||
"recurring_todo" =>
|
||||
{
|
||||
"daily_every_x_days"=>"1",
|
||||
"daily_selector"=>"daily_every_x_day",
|
||||
"description"=>"new recurring pattern",
|
||||
"end_date" => nil,
|
||||
"ends_on" => "no_end_date",
|
||||
"monthly_day_of_week" => "2",
|
||||
"monthly_every_x_day" => "2",
|
||||
"monthly_every_x_month2" => "1",
|
||||
"monthly_every_x_month" => "3",
|
||||
"monthly_every_xth_day"=>"1",
|
||||
"monthly_selector"=>"monthly_every_x_day",
|
||||
"notes"=>"with some notes",
|
||||
"number_of_occurences" => nil,
|
||||
"recurring_period"=>"monthly",
|
||||
"recurring_show_days_before"=>"0",
|
||||
"recurring_target"=>"show_from_date",
|
||||
"recurring_show_always" => "1",
|
||||
"start_from"=>"2/1/2013",
|
||||
"weekly_every_x_week"=>"1",
|
||||
"weekly_return_monday"=>"m",
|
||||
"yearly_day_of_week"=>"1",
|
||||
"yearly_every_x_day"=>"8",
|
||||
"yearly_every_xth_day"=>"1",
|
||||
"yearly_month_of_year2"=>"8",
|
||||
"yearly_month_of_year"=>"6",
|
||||
"yearly_selector"=>"yearly_every_x_day"
|
||||
},
|
||||
"tag_list"=>"one, two, three, four"
|
||||
|
||||
assert_equal "new recurring pattern", assigns['recurring_todo'].description
|
||||
assert_equal "2013-01-02 00:00:00 +0000", assigns['recurring_todo'].start_from.to_s
|
||||
todo = assigns['recurring_todo'].todos.first
|
||||
assert_equal "2013-01-02 00:00:00 +0000", todo.show_from.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def test_find_and_inactivate
|
||||
login_as(:admin_user)
|
||||
|
||||
|
|
|
@ -121,6 +121,28 @@ class TodosControllerTest < ActionController::TestCase
|
|||
assert_equal 3, @tagged
|
||||
end
|
||||
|
||||
def test_find_tagged_with_terms_separated_with_dot
|
||||
login_as :admin_user
|
||||
create_todo(description: "test dotted tag", tag_list: "first.last, second")
|
||||
t = assigns['todo']
|
||||
assert_equal "first.last, second", t.tag_list
|
||||
|
||||
get :tag, name: 'first.last.m'
|
||||
assert_equal "text/html", request.format, "controller should set right content type"
|
||||
assert_equal "text/html", @response.content_type
|
||||
assert_equal "first.last", assigns['tag_name'], ".m should be chomped"
|
||||
|
||||
get :tag, name: 'first.last.txt'
|
||||
assert_equal "text/plain", request.format, "controller should set right content type"
|
||||
assert_equal "text/plain", @response.content_type
|
||||
assert_equal "first.last", assigns['tag_name'], ".txt should be chomped"
|
||||
|
||||
get :tag, name: 'first.last'
|
||||
assert_equal "text/html", request.format, "controller should set right content type"
|
||||
assert_equal "text/html", @response.content_type
|
||||
assert_equal "first.last", assigns['tag_name'], ":name should be correct"
|
||||
end
|
||||
|
||||
def test_get_boolean_expression_from_parameters_of_tag_view_single_tag
|
||||
login_as(:admin_user)
|
||||
get :tag, :name => "single"
|
||||
|
@ -669,7 +691,7 @@ class TodosControllerTest < ActionController::TestCase
|
|||
recurring_todo_1 = RecurringTodo.find(1)
|
||||
#set_user_to_current_time_zone(recurring_todo_1.user)
|
||||
todo_1 = Todo.where(:recurring_todo_id => 1).first
|
||||
today = Time.zone.now.at_midnight
|
||||
today = Time.zone.now.at_midnight - 1.day
|
||||
|
||||
# change recurrence pattern to monthly and set show_from to today
|
||||
recurring_todo_1.target = 'show_from_date'
|
||||
|
@ -708,7 +730,7 @@ class TodosControllerTest < ActionController::TestCase
|
|||
assert !new_todo.show_from.nil?
|
||||
|
||||
# do not use today here. It somehow gets messed up with the timezone calculation.
|
||||
next_month = (Time.zone.now + 1.month).at_midnight
|
||||
next_month = (Time.zone.now - 1.day + 1.month).at_midnight
|
||||
|
||||
assert_equal next_month.utc.to_date.to_s(:db), new_todo.show_from.utc.to_date.to_s(:db)
|
||||
end
|
||||
|
@ -920,4 +942,19 @@ class TodosControllerTest < ActionController::TestCase
|
|||
assert t4.pending?, "t4 should remain pending"
|
||||
assert t4.predecessors.map(&:id).include?(t3.id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_todo(params={})
|
||||
defaults = { source_view: 'todo',
|
||||
context_name: "library", project_name: "Build a working time machine",
|
||||
notes: "note", description: "a new todo", due: nil, tag_list: "a,b,c"}
|
||||
|
||||
params=params.reverse_merge(defaults)
|
||||
|
||||
put :create, _source_view: params[:_source_view],
|
||||
context_name: params[:context_name], project_name: params[:project_name], tag_list: params[:tag_list],
|
||||
todo: {notes: params[:notes], description: params[:description], due: params[:due]}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -175,6 +175,9 @@ class RecurringTodoTest < ActiveSupport::TestCase
|
|||
assert_equal @sunday, due_date # june 8th
|
||||
|
||||
due_date = @monthly.get_due_date(@sunday) # june 8th
|
||||
assert_equal Time.zone.local(2008,6,8), due_date # june 8th
|
||||
|
||||
due_date = @monthly.get_due_date(@monday) # june 9th
|
||||
assert_equal Time.zone.local(2008,8,8), due_date # aug 8th
|
||||
end
|
||||
|
||||
|
|
|
@ -11,6 +11,6 @@ class TaggingTest < ActiveSupport::TestCase
|
|||
|
||||
tagging.destroy
|
||||
|
||||
assert_nil Tag.where(:name => "hello").first
|
||||
assert_nil Tag.where(:name => "hello").first, "Tag should be destroyed when last use in tagging was removed"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -239,6 +239,26 @@ class TodoTest < ActiveSupport::TestCase
|
|||
assert !@not_completed1.starred?
|
||||
end
|
||||
|
||||
def test_hidden_todo_remains_hidden_after_getting_unblokked
|
||||
todo = todos(:call_bill)
|
||||
project=todo.project
|
||||
project.hide!
|
||||
|
||||
assert todo.reload.hidden?, "todo in hidden project should be hidden"
|
||||
|
||||
todo2 = todos(:call_dino_ext)
|
||||
todo.add_predecessor(todo2)
|
||||
todo.block!
|
||||
|
||||
assert todo.pending?, "todo with predecessor should be blocked"
|
||||
|
||||
# cannot activate if part of hidden project
|
||||
assert_raise(AASM::InvalidTransition) { todo.activate! }
|
||||
|
||||
todo.remove_predecessor(todo2)
|
||||
assert todo.reload.hidden?, "todo should be put back in hidden state"
|
||||
end
|
||||
|
||||
def test_todo_specification_handles_null_project
|
||||
# @not_completed1 has a project
|
||||
todo_desc = @not_completed1.description
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue