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 …</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 {