diff --git a/Gemfile b/Gemfile index 6638f39b..e4f5bdad 100644 --- a/Gemfile +++ b/Gemfile @@ -17,16 +17,11 @@ gem "rubycas-client", "~>2.2.1" gem "ruby-openid", :require => "openid" gem "sqlite3" gem 'bcrypt-ruby', '~> 2.1.4' -gem 'htmlentities', '~> 4.3.0' gem "webrat", ">=0.7.0", :groups => [:cucumber, :test] gem "database_cleaner", ">=0.5.0", :groups => [:cucumber, :selenium] gem "cucumber-rails", "~>0.3.0", :groups => :cucumber -group :development do - gem "ruby-debug" -end - group :test do gem "flexmock" gem "ZenTest", ">=4.0.0" diff --git a/Gemfile.lock b/Gemfile.lock index 7b77064a..a952d7a4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -27,7 +27,6 @@ GEM bcrypt-ruby (2.1.4) builder (3.0.0) cgi_multipart_eof_fix (2.5.0) - columnize (0.3.4) cucumber (1.0.2) builder (>= 2.1.2) diff-lcs (>= 1.1.2) @@ -50,11 +49,8 @@ GEM hoe (2.12.0) rake (~> 0.8) hpricot (0.8.4) - htmlentities (4.3.0) httpclient (2.2.1) json (1.5.3) - linecache (0.46) - rbx-require-relative (> 0.0.4) memory_test_fix (0.1.3) mongrel (1.1.5) cgi_multipart_eof_fix (>= 2.4) @@ -73,16 +69,10 @@ GEM activesupport (= 2.3.14) rake (>= 0.8.3) rake (0.8.7) - rbx-require-relative (0.0.5) rspec (1.3.2) rspec-rails (1.3.4) rack (>= 1.0.0) rspec (~> 1.3.1) - ruby-debug (0.10.4) - columnize (>= 0.1) - ruby-debug-base (~> 0.10.4.0) - ruby-debug-base (0.10.4) - linecache (>= 0.3) ruby-openid (2.1.8) rubycas-client (2.2.1) activesupport @@ -117,14 +107,12 @@ DEPENDENCIES highline (~> 1.5.0) hoe hpricot - htmlentities (~> 4.3.0) memory_test_fix (~> 0.1.3) mongrel rack (= 1.1.0) rails (~> 2.3.12) rake (~> 0.8.7) rspec-rails (~> 1.3.3) - ruby-debug ruby-openid rubycas-client (~> 2.2.1) sanitize (~> 1.2.1) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 5f681aa4..821d1f79 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -33,6 +33,37 @@ class ProjectsController < ApplicationController end end + def review + ## select project that need reviewing + @projects_to_review = current_user.projects.select {|p| p.needs_review?(current_user)} + + ## select project that are stalled + @stalled_projects = current_user.projects.select {|p| p.stalled?} + + ## select project that are stalled + @blocked_projects = current_user.projects.select {|p| p.blocked?} + + + + + @contexts = current_user.contexts.all + init_not_done_counts(['project']) + init_project_hidden_todo_counts(['project']) + if params[:only_active_with_no_next_actions] + @projects = current_user.projects.active.select { |p| count_undone_todos(p) == 0 } + else + @projects = current_user.projects.all + end + + @page_title = t('projects.list_reviews') + @count = @projects_to_review.count + @blocked_projects.count + @stalled_projects.count + + @no_projects = current_user.projects.empty? + current_user.projects.cache_note_counts + @new_project = current_user.projects.build + render + end + def done @source_view = params['_source_view'] || 'project_list' @page_title = t('projects.list_completed_projects') @@ -51,6 +82,13 @@ class ProjectsController < ApplicationController render end + def set_reviewed + @project = current_user.projects.find(params[:id]) + @project.last_reviewed = Time.now + @project.save + redirect_to :action => 'show' + end + def projects_and_actions @projects = current_user.projects.active respond_to do |format| diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 5773e5c8..aadb3303 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -67,4 +67,14 @@ module ProjectsHelper project_description end + def needsreview_class(item) + raise "item must be a Project " unless item.kind_of? Project + + if item.needs_review?(current_user) + return "needsreview" + else + return "needsnoreview" + end + end + end diff --git a/app/models/project.rb b/app/models/project.rb index c78e6ccb..a24f9f44 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -107,6 +107,34 @@ class Project < ActiveRecord::Base end end + def needs_review?(current_user) + return false unless !nil? + return true if last_reviewed.nil? + return (active? && (last_reviewed < current_user.time - current_user.prefs.review_period.days)) + end + + def blocked? + ## mutually exclusive for stalled and blocked + return false if stalled? + return false if completed? + is_blocked = true + todos.each do |t| + is_blocked = false if (!t.completed? && !t.deferred? && !t.pending?) + end + return is_blocked + end + + def stalled? + return true if todos.count == 0 + return false if completed? + is_stalled = true + todos.each do |t| + is_stalled = false if (!t.completed?) + end + return is_stalled + end + + def name=(value) self[:name] = value.gsub(/\s{2,}/, " ").strip end diff --git a/app/views/layouts/standard.html.erb b/app/views/layouts/standard.html.erb index 86409650..f47cfa96 100644 --- a/app/views/layouts/standard.html.erb +++ b/app/views/layouts/standard.html.erb @@ -64,6 +64,7 @@ diff --git a/app/views/preferences/_tracks_behavior.html.erb b/app/views/preferences/_tracks_behavior.html.erb index 480b647f..b4937187 100644 --- a/app/views/preferences/_tracks_behavior.html.erb +++ b/app/views/preferences/_tracks_behavior.html.erb @@ -5,6 +5,7 @@ <%= pref_with_select_field('prefs', "show_hidden_contexts_in_sidebar") %> <%= pref_with_select_field('prefs', "show_project_on_todo_done") %> <%= pref_with_text_field('prefs', 'staleness_starts') %> +<%= pref_with_text_field('prefs', 'review_period') %> <%= pref_with_text_field('prefs', 'show_number_completed') %> <%= pref_with_text_field('prefs', 'refresh') %> <%= pref_with_select_field('prefs', "verbose_action_descriptors") %> diff --git a/app/views/projects/_edit_project.rhtml b/app/views/projects/_edit_project.rhtml new file mode 100644 index 00000000..41927dd5 --- /dev/null +++ b/app/views/projects/_edit_project.rhtml @@ -0,0 +1,6 @@ +<%= hidden_field( "project", "id" ) %> +MUUUUUAAHAHAHAHAH!!!! +
+<%= text_field( "project", "name" ) %> +
+
\ No newline at end of file diff --git a/app/views/projects/_project_form.rhtml b/app/views/projects/_project_form.rhtml index f6b67b6c..46630cff 100644 --- a/app/views/projects/_project_form.rhtml +++ b/app/views/projects/_project_form.rhtml @@ -40,6 +40,10 @@ project = project_form <%=image_tag("cancel.png", :alt => "") %> Cancel + " id="<%= dom_id(project, 'reviewed') %>" class="reviewed"> + <%=image_tag("reviewed.png", :alt => "") %> + Reviewed +

diff --git a/app/views/projects/_project_listing.rhtml b/app/views/projects/_project_listing.rhtml index b07bf0c3..3d452c54 100644 --- a/app/views/projects/_project_listing.rhtml +++ b/app/views/projects/_project_listing.rhtml @@ -12,8 +12,12 @@ suppress_edit_button ||= false <% end -%> +
- <%= link_to_project( project ) %><%= " (" + count_undone_todos_and_notes_phrase(project,"actions") + ")" %> + + <%= link_to_project( project ) %> + <%= " (" + count_undone_todos_and_notes_phrase(project,"actions") + ")" %> +
diff --git a/app/views/projects/_project_state_group.rhtml b/app/views/projects/_project_state_group.rhtml index beb7d882..65e15230 100644 --- a/app/views/projects/_project_state_group.rhtml +++ b/app/views/projects/_project_state_group.rhtml @@ -5,7 +5,11 @@
>

<%= project_state_group.length%><%= total_count_string%> - <%= t('common.last' )%> <%= t('states.'+state+'_plural' )%> <%= t('common.projects') %><%= total_count==-1 ? "" : " ("+link_to("Show all", done_projects_path)+")"%> + + <%= t('common.last' ) unless (state == 'review' || state == 'stalled' || state == 'blocked')%> + <%= t('states.'+state+'_plural' )%> + <%= t('common.projects') %><%= total_count==-1 ? "" : " ("+link_to("Show all", done_projects_path)+")"%> +

diff --git a/app/views/projects/review.html.erb b/app/views/projects/review.html.erb new file mode 100644 index 00000000..201e792d --- /dev/null +++ b/app/views/projects/review.html.erb @@ -0,0 +1,6 @@ +
+

<%= t('projects.no_projects') %>

+
+ <%= render :partial => 'project_state_group', :object => @projects_to_review, :locals => { :state => 'review'} %> + <%= render :partial => 'project_state_group', :object => @stalled_projects, :locals => { :state => 'stalled'} %> + <%= render :partial => 'project_state_group', :object => @blocked_projects, :locals => { :state => 'blocked'} %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 51c46084..42f0411f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -22,6 +22,7 @@ en: feeds: Feeds starred: Starred notes_title: Show all notes + review_title: Make review stats: Statistics tickler_title: Tickler manage_users: Manage users @@ -102,6 +103,7 @@ en: server_error: An error occurred on the server. forum: Forum notes: Notes + review: Review last: Last projects: Projects action: Action @@ -579,6 +581,12 @@ en: active_plural: Active hidden: Hidden active: Active + review_plural: Dated + review: Dated + stalled_plural: Stalled + stalled: Stalled + blocked_plural: Blocked + blocked: Blocked projects: was_marked_hidden: has been marked as hidden edit_project_title: Edit project @@ -616,6 +624,7 @@ en: completed_projects: Completed projects with_default_tags: and with '%{tags}' as the default tags list_projects: TRACKS::List Projects + list_reviews: TRACKS::Review project_saved_status: Project saved add_project: Add Project add_note: Add a note diff --git a/config/routes.rb b/config/routes.rb index 1838b1bc..c642eb35 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -13,10 +13,15 @@ ActionController::Routing::Routes.draw do |map| end map.resources :projects, :collection => {:order => :post, :alphabetize => :post, :actionize => :post, :done => :get}, - :member => {:done_todos => :get, :all_done_todos => :get} do |projects| + :member => {:done_todos => :get, :all_done_todos => :get, :set_reviewed => :get} do |projects| projects.resources :todos, :name_prefix => "project_" end + map.with_options :controller => :projects do |projects| + # projects.home '', :action => "index" + projects.review 'review', :action => :review + end + map.resources :notes map.resources :todos, @@ -24,6 +29,7 @@ ActionController::Routing::Routes.draw do |map| :collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post, :done => :get, :all_done => :get } + map.with_options :controller => :todos do |todos| todos.home '', :action => "index" todos.tickler 'tickler.:format', :action => "list_deferred" diff --git a/db/migrate/20110915100000_add_last_reviewed_to_project.rb b/db/migrate/20110915100000_add_last_reviewed_to_project.rb new file mode 100644 index 00000000..e6d84814 --- /dev/null +++ b/db/migrate/20110915100000_add_last_reviewed_to_project.rb @@ -0,0 +1,9 @@ +class AddLastReviewedToProject < ActiveRecord::Migration + def self.up + add_column :projects, :last_reviewed, :timestamp + execute 'update projects set last_reviewed = created_at where last_reviewed IS NULL' + end + def self.down + remove_column :projects, :last_reviewed + end +end diff --git a/db/migrate/20110915100001_add_next_review_preferences.rb b/db/migrate/20110915100001_add_next_review_preferences.rb new file mode 100644 index 00000000..633c765d --- /dev/null +++ b/db/migrate/20110915100001_add_next_review_preferences.rb @@ -0,0 +1,8 @@ +class AddNextReviewPreferences < ActiveRecord::Migration + def self.up + add_column :preferences, :review_period, :integer, :default => 14, :null => false + end + def self.down + remove_column :preferences, :review_period + end +end diff --git a/features/support/paths.rb b/features/support/paths.rb index 65579a71..1c06e6ee 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -61,6 +61,9 @@ module NavigationHelpers notes_path(options) when /the calendar page/ calendar_path(options) + when /the review page/ + @source_view = "review" + review_path(options) when /the contexts page/ @source_view = "contexts" contexts_path(options) diff --git a/public/images/reviewed.png b/public/images/reviewed.png new file mode 100755 index 00000000..9c4495be Binary files /dev/null and b/public/images/reviewed.png differ diff --git a/public/stylesheets/standard.css b/public/stylesheets/standard.css index 8a1ab422..36b21d4d 100644 --- a/public/stylesheets/standard.css +++ b/public/stylesheets/standard.css @@ -1,3 +1,11 @@ +.needsreview { + background: #ffC; +} + +.widgets a.reviewed, button.reviewed { + float:right; +} + div.depends_on label { float: left; }