Author: assaf
Date: Wed May 14 22:30:14 2008
New Revision: 656512

URL: http://svn.apache.org/viewvc?rev=656512&view=rev
Log:
Preliminary task list view.

Modified:
    ode/sandbox/singleshot/app/controllers/tasks_controller.rb
    ode/sandbox/singleshot/app/models/task.rb
    ode/sandbox/singleshot/app/views/layouts/application.html.erb
    ode/sandbox/singleshot/app/views/tasks/index.html.erb
    ode/sandbox/singleshot/config/routes.rb
    ode/sandbox/singleshot/lib/tasks/database.rake
    ode/sandbox/singleshot/public/stylesheets/default.css

Modified: ode/sandbox/singleshot/app/controllers/tasks_controller.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/controllers/tasks_controller.rb?rev=656512&r1=656511&r2=656512&view=diff
==============================================================================
--- ode/sandbox/singleshot/app/controllers/tasks_controller.rb (original)
+++ ode/sandbox/singleshot/app/controllers/tasks_controller.rb Wed May 14 
22:30:14 2008
@@ -5,11 +5,14 @@
   instance :task, :only=>[:show, :update, :complete, :destroy], 
:check=>:instance_accessible
   before_filter :forbid_reserved, :except=>[:update, :destroy]
 
-  layout 'head', :only=>[:show]
-  layout 'application', :only=>[:index]
+  layout 'application'
 
   def index
-    @tasks = Task.for_stakeholder(authenticated)
+    @tasks = 
Task.with_stakeholders.for_stakeholder(authenticated).pending.prioritized
+  end
+
+  def following
+    @tasks = Task.with_stakeholders.for_stakeholder(authenticated).following
   end
 
   def new

Modified: ode/sandbox/singleshot/app/models/task.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/models/task.rb?rev=656512&r1=656511&r2=656512&view=diff
==============================================================================
--- ode/sandbox/singleshot/app/models/task.rb (original)
+++ ode/sandbox/singleshot/app/models/task.rb Wed May 14 22:30:14 2008
@@ -27,7 +27,7 @@
   def initialize(attributes = {}) #:nodoc:
     super
     self.description ||= ''
-    self.state = 'reserved'
+    self.state = attributes[:state] == 'ready' ? 'ready' : 'reserved'
     self.data ||= {}
     self.access_key = MD5.hexdigest(OpenSSL::Random.random_bytes(128))
   end
@@ -71,6 +71,12 @@
   attr_protected :state
   validates_inclusion_of :state, :in=>STATES
 
+  STATES.each do |state|
+    define_method "#{state}?" do
+      self.state == state
+    end
+  end
+
   before_validation_on_update do |task|
     task.state = 'ready' if task.state == 'reserved'
   end
@@ -100,8 +106,6 @@
     end
   end
 
-  named_scope :active, :conditions=>{ :state=>'active' }
-  named_scope :completed, :conditions=>{ :state=>'completed' }
 
 
   # -- Common task attributes --
@@ -139,13 +143,23 @@
   include Stakeholder::Accessors
   include Stakeholder::Validation
 
+  named_scope :with_stakeholders, :include=>{ :stakeholders=>:person }
+
   named_scope :for_stakeholder, lambda { |person|
-    { :joins=>'INNER JOIN stakeholders AS involved ON 
involved.task_id=tasks.id', :conditions=>['stakeholders.person_id=?', 
person.id], :include=>[:stakeholders] }
+    { :joins=>'JOIN stakeholders AS involved ON involved.task_id=tasks.id', 
:conditions=>['involved.person_id=?', person.id], :include=>:stakeholders }
   }
   named_scope :for_owner,       lambda { |person|
     { :joins=>:stakeholders, :conditions=>["stakeholders.person_id=? and 
stakeholders.role='owner'", person.id] }
   }
 
+  named_scope :pending, :conditions=>["tasks.state IN ('ready', 'active') AND 
involved.role IN ('owner', 'potential')"],
+    :order=>'involved.role, priority DESC, tasks.created_at' do
+    def prioritized
+      today = Date.today
+      prioritize = lambda { |task| [task.state == 'active' ? 0 : 1, 
task.due_on && task.due_on <= today ? task.due_on - today : 1, -task.priority] }
+      self.sort { |a, b| prioritize[a] <=> prioritize[b] }
+    end
+  end
 
   # --- Priority and ordering ---
   
@@ -154,6 +168,10 @@
   before_validation { |task| task.priority ||= PRIORITIES.min }
   validates_inclusion_of :priority, :in=>PRIORITIES
 
+  def over_due?
+    due_on && due_on < Date.today
+  end
+
  
   # --- Completion and cancellation ---
 
@@ -203,9 +221,10 @@
 
   # Returns true if this person can cancel this task.
   def can_cancel?(person)
-    return false if completed?
-    return true if person.admin? || admin?(person)
-    return owner?(person) if cancellation == :owner
+    return false if state == 'completed' || state == 'cancelled'
+    #return true if person.admin? || admin?(person)
+    #return owner?(person) if cancellation == :owner
+    return true if admin?(person)
     false
   end
 
@@ -215,7 +234,7 @@
   end
 
   def can_suspend?(person)
-    admin?(person) || person.admin?
+    admin?(person) # || person.admin?
   end
 
   def can_claim?(person)

Modified: ode/sandbox/singleshot/app/views/layouts/application.html.erb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/views/layouts/application.html.erb?rev=656512&r1=656511&r2=656512&view=diff
==============================================================================
--- ode/sandbox/singleshot/app/views/layouts/application.html.erb (original)
+++ ode/sandbox/singleshot/app/views/layouts/application.html.erb Wed May 14 
22:30:14 2008
@@ -10,19 +10,18 @@
   </head>
   <body>
     <div id='header'>
-      <h1>Singleshot</h1>
+      <h1><%= link_to 'Singleshot', root_url %></h1>
       <ul id='personal'>
         <li><a href='#'>Help</a></li>
         <li><a href='#'>Settings</a></li>
         <li><%= link_to 'Logout', session_url(:method=>:delete) %></li>
       </ul>
       <ul id='navigation'>
-        <li><a href='#'>Dashboard</a></li>
-        <li><a href='#'>Tasks</a></li>
-        <li><a href='#'>Notifications</a></li>
-        <li><a href='#'>Completed</a></li>
-        <li><a href='#'>Tracking</a></li>
-        <li><a href='#'>Activities</a></li>
+        <li><%= link_to '➠ Tasks', tasks_url %></li>
+        <li><%= link_to 'Following', following_tasks_url %></a></li>
+        <li><%= link_to 'Completed', completed_tasks_url %></a></li>
+        <li><a href='#'>Activity</a></li>
+        <li><a href='#'>Start &hellip;</a></li>
       </ul>
     </div>
     <div id='main'>

Modified: ode/sandbox/singleshot/app/views/tasks/index.html.erb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/views/tasks/index.html.erb?rev=656512&r1=656511&r2=656512&view=diff
==============================================================================
--- ode/sandbox/singleshot/app/views/tasks/index.html.erb (original)
+++ ode/sandbox/singleshot/app/views/tasks/index.html.erb Wed May 14 22:30:14 
2008
@@ -2,17 +2,18 @@
   <% @tasks.each do |task| %>
     <% content_tag_for 'li', task do %>
       <div class='actions'>
-        <%= button_to 'Claim', task, :title=>'Claim task' %>
-        <%= button_to 'Edit', edit_task_url(task), :method=>:get, 
:title=>'Edit task' %>
-        <%= button_to 'Cancel', task_url(task), :method=>:delete, 
:disabled=>true, :title=>'Cancel this task' %>
+        <%= button_to 'Edit', edit_task_url(task), :method=>:get, 
:title=>'Edit task' if task.admin?(authenticated) %>
+        <%= button_to 'Cancel', task_url(task), :method=>:delete, 
:title=>'Cancel this task' if task.can_cancel?(authenticated) %>
+        <%= button_to 'Claim', task, :title=>'Claim task', 
:disabled=>!task.can_claim?(authenticated) if task.active? || task.ready? %>
       </div>
-      <h3 class='title'><%= link_to h(task.title), task_url(task), 
:title=>'View/perform task' %></h3>
+      <h3 class='title priority_<%= task.priority %> <%= 'overdue' if 
task.over_due? %>'><%= link_to h(task.title), task_url(task), 
:title=>'View/perform task' %></h3>
       <p class='description'><%= h(task.description) %></p>
       <p class='stats'>
       <%=
       stats = ['Created ' + task.created_at.to_date.to_formatted_s(:long)]
       stats << 'by ' + link_to(task.creator.fullname, task.creator.identity) 
if task.creator
       stats << 'assigned to ' + link_to(task.owner.fullname, 
task.owner.identity) if task.owner
+      stats << "due on #{task.due_on.to_formatted_s(:long)}" if task.due_on
       stats.to_sentence
       %>
       </p>

Modified: ode/sandbox/singleshot/config/routes.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/config/routes.rb?rev=656512&r1=656511&r2=656512&view=diff
==============================================================================
--- ode/sandbox/singleshot/config/routes.rb (original)
+++ ode/sandbox/singleshot/config/routes.rb Wed May 14 22:30:14 2008
@@ -1,15 +1,10 @@
 ActionController::Routing::Routes.draw do |map|
 
-  map.resource :session
-  map.resources :tasks
-  map.with_options :controller=>'tasks', :action=>'complete', :conditions=>{ 
:method=>:post },
-                   :id=>/[^#{ActionController::Routing::SEPARATORS.join}]+/ do 
|task|
-    task.connect '/tasks/:id'
-    task.connect '/tasks/:id.:format'
-  end
-  map.resource :sandwich
+  map.resource 'session'
+  map.resources 'tasks', :collection=>{ 'following'=>:get, 'completed'=>:get }
   map.root :controller=>'tasks'
-  map.connect ':controller/:action/:id'
+  map.resource 'sandwich'
+  #map.connect ':controller/:action/:id'
   
 
   # Authentication resource (create/destroy).

Modified: ode/sandbox/singleshot/lib/tasks/database.rake
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/lib/tasks/database.rake?rev=656512&r1=656511&r2=656512&view=diff
==============================================================================
--- ode/sandbox/singleshot/lib/tasks/database.rake (original)
+++ ode/sandbox/singleshot/lib/tasks/database.rake Wed May 14 22:30:14 2008
@@ -7,20 +7,42 @@
 
   desc 'Populate the database with mock values'
   task 'populate'=>['environment', 'create', 'migrate'] do
-    person = Person.find_by_identity(ENV['USER'])
-    unless person
-      person = Person.create(:email=>"#{ENV['USER'[EMAIL PROTECTED]", 
:password=>'secret')
+    you = Person.find_by_identity(ENV['USER'])
+    unless you
+      you = Person.create(:email=>"#{ENV['USER'[EMAIL PROTECTED]", 
:password=>'secret')
       puts 'Created an account for you:'
       puts "  Username: #{ENV['USER']}"
       puts '  Password: secret'
     end
 
-    puts "Populating database for #{person.identity}"
-    creator = Person.identify('creator') || Person.create(:email=>'[EMAIL 
PROTECTED]')
-    (1..3).each do |i|
-      Task.create! :title=>Faker::Lorem.sentence, 
:description=>Faker::Lorem.paragraph,  
-        :frame_url=>'http://localhost:3001/sandwhich', :owner=>person, 
:creator=>creator
-    end
+    puts "Populating database for #{you.identity}"
+    url = 'http://localhost:3001/sandwhich'
+    other = Person.identify('anon') || Person.create(:email=>'[EMAIL 
PROTECTED]')
+    default = lambda { |attributes| { :title=>Faker::Lorem.sentence, 
:description=>Faker::Lorem.paragraph,
+                                      :frame_url=>url, :state=>'ready' 
}.merge(attributes || {}) }
+
+    # Tasks you should not see.
+    Task.create! default[:title=>'You will not see this task since this task 
is reserved.', :state=>'reserved', :creator=>you]
+    Task.create! default[:title=>'You will not see this task since you are not 
a stakeholder.']
+    # Tasks in which we are:
+    # - creator
+    # - owner
+    # - observer
+    # - admin
+    Task.create! default[:creator=>you]
+    Task.create! default[:owner=>you]
+    Task.create! default[:observers=>you]
+    Task.create! default[:admins=>you]
+    # Tasks in which we are only or one of many potential owners.
+    Task.create! default[:potential_owners=>you]
+    Task.create! default[:potential_owners=>[you, other]]
+    Task.create! default[:title=>'Invisible', :owner=>other, 
:potential_owners=>you]
+    # High priority should show first.
+    Task.create! default[:owner=>you, :priority=>3]
+    # Over-due before due today before anything else.
+    Task.create! default[:owner=>you, :due_on=>Time.today - 1.day]
+    Task.create! default[:owner=>you, :due_on=>Time.today]
+    Task.create! default[:owner=>you, :due_on=>Time.today + 1.day]
   end
 
 end

Modified: ode/sandbox/singleshot/public/stylesheets/default.css
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/public/stylesheets/default.css?rev=656512&r1=656511&r2=656512&view=diff
==============================================================================
--- ode/sandbox/singleshot/public/stylesheets/default.css (original)
+++ ode/sandbox/singleshot/public/stylesheets/default.css Wed May 14 22:30:14 
2008
@@ -150,6 +150,10 @@
   margin: 0 auto 1em auto;
   float: left;
 }
+#header h1 a {
+  color: #000;
+  text-decoration: none;
+}
 #header ul#personal {
   list-style: none;
   float: right;
@@ -189,6 +193,17 @@
 #header ul#navigation li a:hover {
   background-color: #002f2f;
 }
+#header ul#navigation li a .counter {
+  position: relative;
+  top: -1.1em;
+  right: -1em;
+  font-size: 0.5em;
+  margin: 0;
+  padding: 0.3em;
+  background-color: red;
+  -moz-border-radius: 0.3em;
+  -webkit-border-top-left-radius: 0.3em;
+}
 
 ol.tasks {
   list-style: none;
@@ -203,6 +218,17 @@
   font-size: 1.2em;
   margin: 0;
 }
+ol.tasks li.task h3.title.priority_2:before {
+  content: '✭ ';
+  color: yellow;
+}
+ol.tasks li.task h3.title.priority_3:before {
+  content: '✭ ';
+  color: red;
+}
+ol.tasks li.task h3.title.overdue a {
+  color: red;
+}
 ol.tasks li.task a {
   text-decoration: none;
 }
@@ -215,6 +241,9 @@
 ol.tasks li.task .actions form {
   margin-left: 0.1em;
 }
+ol.tasks li.task p.stats {
+  color: #808080;
+}
 
 
 form.button-to, form.button-to div {


Reply via email to