mirror of
https://github.com/TracksApp/tracks.git
synced 2026-01-31 13:15:17 +01:00
Added Luke's excellent changes to the feeds (#214). There are now loads of choices for feeds (including ones for individual contexts or projects and for actions due today or in the next 7 days). The list is accessed via the feed icon in the main navigation.
Thanks, Luke! git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@193 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
parent
aa0760f0ef
commit
6dd0f51dbd
13 changed files with 209 additions and 32 deletions
|
|
@ -11,25 +11,84 @@ class FeedController < ApplicationController
|
|||
def index
|
||||
end
|
||||
|
||||
# Builds an RSS feed for the latest 15 items
|
||||
# This is fairly basic: it lists the action description as the title
|
||||
# and the item context as the description
|
||||
#
|
||||
def na_feed
|
||||
@not_done = @user.todos.collect { |x| x.done? ? nil:x }.compact.sort! {|x,y| y.created_at <=> x.created_at }
|
||||
# Build an RSS feed
|
||||
def rss
|
||||
conditions = '(done = 0)'
|
||||
options = {:conditions => conditions}
|
||||
|
||||
limit = @params['limit']
|
||||
options[:limit] = limit if limit
|
||||
@description = limit ? "Lists the last #{limit} uncompleted next actions" : "Lists uncompleted next actions"
|
||||
@title = "Tracks - Next Actions"
|
||||
|
||||
if @params['due']
|
||||
due_within = @params['due'].to_i
|
||||
due_within_date_s = due_within.days.from_now.strftime("%Y-%m-%d")
|
||||
conditions << " AND (due <= '#{due_within_date_s}')"
|
||||
@title << " due today" if (due_within == 0)
|
||||
@title << " due within a week" if (due_within == 6)
|
||||
@description << " with a due date #{due_within_date_s} or earlier"
|
||||
end
|
||||
|
||||
context_id = @params['context']
|
||||
if context_id
|
||||
conditions << " AND (context_id = #{context_id})"
|
||||
context = @user.contexts.find(context_id)
|
||||
@title << " in #{context.name}"
|
||||
@description << " in context '#{context.name}'"
|
||||
end
|
||||
|
||||
project_id = @params['project']
|
||||
if project_id
|
||||
conditions << " AND (project_id = #{project_id})"
|
||||
project = @user.projects.find(project_id)
|
||||
@title << " for #{project.name}"
|
||||
@description << " for project '#{project.name}'"
|
||||
end
|
||||
|
||||
@todos = @user.todos.find_all_by_done(false, options )
|
||||
@headers["Content-Type"] = "text/xml; charset=utf-8"
|
||||
end
|
||||
|
||||
# Builds a plain text page listing all the next actions,
|
||||
# sorted by context (contexts are sorted by position, as on the home page).
|
||||
# Builds a plain text page listing uncompleted next actions,
|
||||
# grouped by context (contexts are sorted by position, as on the home page).
|
||||
# Showing notes doesn't make much sense here so they are omitted.
|
||||
# Hidden contexts are also hidden in the text view
|
||||
# You can use this with GeekTool to get your next actions
|
||||
# on the desktop:
|
||||
# curl [url from "TXT" link on todo/list]
|
||||
#
|
||||
def na_text
|
||||
@contexts = @user.contexts.collect { |x| x.hide? ? nil:x }.compact.sort! { |x,y| x.position <=> y.position }
|
||||
def text
|
||||
conditions = '(done = 0)'
|
||||
options = {:conditions => conditions}
|
||||
|
||||
limit = @params['limit']
|
||||
options[:limit] = limit if limit
|
||||
|
||||
if @params['due']
|
||||
due_within = @params['due'].to_i
|
||||
due_within_date_s = due_within.days.from_now.strftime("%Y-%m-%d")
|
||||
conditions << " AND (due <= '#{due_within_date_s}')"
|
||||
end
|
||||
|
||||
context_id = @params['context']
|
||||
if context_id
|
||||
conditions << " AND (context_id = #{context_id})"
|
||||
context = @user.contexts.find(context_id)
|
||||
@contexts = [context]
|
||||
end
|
||||
|
||||
project_id = @params['project']
|
||||
if project_id
|
||||
conditions << " AND (project_id = #{project_id})"
|
||||
project = @user.projects.find(project_id)
|
||||
end
|
||||
|
||||
@todos = @user.todos.find_all_by_done(false, options )
|
||||
|
||||
if (!@contexts)
|
||||
@contexts = @user.contexts.find_all_by_hide(false)
|
||||
end
|
||||
@headers["Content-Type"] = "text/plain; charset=utf-8"
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -189,6 +189,11 @@ class TodoController < ApplicationController
|
|||
archive_date = Time.now - 32 * (60 * 60 * 24)
|
||||
@done_archive = @done.collect { |x| archive_date >= x.completed ? x:nil }.compact
|
||||
end
|
||||
|
||||
def feeds
|
||||
self.init
|
||||
@page_title = "TRACKS::Feeds"
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@ module FeedHelper
|
|||
#
|
||||
def build_text_page(list,context)
|
||||
result_string = ""
|
||||
result_string << "\n" + context.name.upcase + ":\n"
|
||||
|
||||
list.each do |item|
|
||||
list.each do |item|
|
||||
if item.context_id == context.id
|
||||
|
||||
result_string << "\n" + context.name.upcase + ":\n" if result_string.empty?
|
||||
|
||||
if item.due
|
||||
result_string << " [" + format_date(item.due) + "] "
|
||||
result_string << item.description + " "
|
||||
|
|
@ -22,10 +21,9 @@ module FeedHelper
|
|||
if item.project_id
|
||||
result_string << "(" + item.project.name + ")"
|
||||
end
|
||||
result_string << "\n"
|
||||
end
|
||||
|
||||
result_string << "\n"
|
||||
end
|
||||
end
|
||||
return result_string
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -110,4 +110,17 @@ module TodoHelper
|
|||
javascript_tag str
|
||||
end
|
||||
|
||||
def rss_feed_link(options = {})
|
||||
image_tag = image_tag("feed-icon", :size => "16X16", :border => 0, :class => "rss-icon")
|
||||
linkoptions = {:controller => 'feed', :action => 'rss', :name => "#{@session['user']['login']}", :token => "#{@session['user']['word']}"}
|
||||
linkoptions.merge!(options)
|
||||
link_to(image_tag, linkoptions, :title => "RSS feed")
|
||||
end
|
||||
|
||||
def text_feed_link(options = {})
|
||||
linkoptions = {:controller => 'feed', :action => 'text', :name => "#{@session['user']['login']}", :token => "#{@session['user']['word']}"}
|
||||
linkoptions.merge!(options)
|
||||
link_to('<span class="feed">TXT</span>', linkoptions, :title => "Plain text feed" )
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ require 'digest/sha1'
|
|||
class User < ActiveRecord::Base
|
||||
has_many :contexts, :order => "position ASC"
|
||||
has_many :projects, :order => "position ASC"
|
||||
has_many :todos, :order => "completed DESC"
|
||||
has_many :todos, :order => "completed DESC, created_at DESC"
|
||||
has_many :notes, :order => "created_at DESC"
|
||||
|
||||
serialize :preferences
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
<%
|
||||
for @context in @contexts
|
||||
@not_done = @context.find_not_done_todos
|
||||
-%>
|
||||
<%= build_text_page( @not_done, @context ) %>
|
||||
<% end -%>
|
||||
|
|
@ -1,20 +1,21 @@
|
|||
xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
|
||||
xml.channel do
|
||||
xml.title("Tracks - Next Actions")
|
||||
xml.title(@title)
|
||||
xml.link("http://#{@request.host}:#{@request.port}/todo/list")
|
||||
xml.description("Lists the last 15 uncompleted next actions")
|
||||
@not_done.each { |i|
|
||||
xml.description(@description)
|
||||
@todos.each { |i|
|
||||
xml.item do
|
||||
xml.title(i.description)
|
||||
xml.link(url_for(:only_path => false, :controller => 'context', :action => 'show', :name => urlize(i.context.name)))
|
||||
item_notes = sanitize(markdown( i.notes )) if i.notes?
|
||||
due = "<div>Due: #{format_date(i.due)}</div>\n" if i.due?
|
||||
context_link = link_to( i.context.name, { :only_path => false, :controller => "context", :action => "show", :name => urlize(i.context.name) } )
|
||||
project_link = if i.project_id?
|
||||
link_to (i.project.name, { :only_path => false, :controller => "project", :action => "show", :name => urlize(i.project.name)} )
|
||||
else
|
||||
"<em>none</em>"
|
||||
end
|
||||
xml.description("#{item_notes||''}\n<div>Project: #{project_link}</div>\n<div>Context: #{context_link}</div>")
|
||||
xml.description("#{due||''}#{item_notes||''}\n<div>Project: #{project_link}</div>\n<div>Context: #{context_link}</div>")
|
||||
end
|
||||
}
|
||||
end
|
||||
5
tracks/app/views/feed/text.rhtml
Normal file
5
tracks/app/views/feed/text.rhtml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<%
|
||||
for @context in @contexts
|
||||
-%>
|
||||
<%= build_text_page( @todos, @context ) %>
|
||||
<% end -%>
|
||||
|
|
@ -35,8 +35,7 @@
|
|||
<li><%= link_to( "Preferences", {:controller => "user", :action => "preferences"}, :title => "Show my preferences" ) %></li>
|
||||
<li><a href="javascript:toggleAll('notes','block')" accesskey="S" title="Show all notes">Show</a></li>
|
||||
<li><a href="javascript:toggleAll('notes','none')" accesskey="H" title="Hide all notes">Hide</a></li>
|
||||
<li><%= link_to(image_tag("feed-icon", :size => "16X16", :border => 0), {:controller => "feed", :action => "na_feed", :name => "#{@session['user']['login']}", :token => "#{@session['user']['word']}"}, :title => "Subscribe to an RSS feed of your next actions" ) %></li>
|
||||
<li><%= link_to("<span class=\"feed\">TXT</span>", {:controller => "feed", :action => "na_text", :name => "#{@session['user']['login']}", :token => "#{@session['user']['word']}"}, :title => "View a plain text feed of your next actions" ) %></li>
|
||||
<li><%= link_to(image_tag("feed-icon", :size => "16X16", :border => 0), {:controller => "todo", :action => "feeds"}, :title => "See a list of available feeds" ) %></li>
|
||||
<li><%= link_to "Logout (#{@session['user']['login']}) »", :controller => "login", :action=>"logout"%></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
67
tracks/app/views/todo/feeds.rhtml
Normal file
67
tracks/app/views/todo/feeds.rhtml
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<div id="display_box">
|
||||
|
||||
<% for name in ["notice", "warning", "message"] %>
|
||||
<% if flash[name] %>
|
||||
<%= "<div id=\"#{name}\">#{flash[name]}</div>" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<div id="feeds">
|
||||
<div id="feedlegend">
|
||||
<h3>Legend:</h3>
|
||||
<dl>
|
||||
<dt><%= image_tag("feed-icon", :size => "16X16", :border => 0)%></dt><dd>RSS Feed</dd>
|
||||
<dt><span class="feed">TXT</span></dt><dd>Plain Text Feed</dd>
|
||||
</dl>
|
||||
<p>Note: All feeds show only actions that have not been marked as done.</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<%= rss_feed_link({ :limit => 15 }) %>
|
||||
<%= text_feed_link({ :limit => 15 }) %>
|
||||
Last 15 actions
|
||||
</li>
|
||||
<li>
|
||||
<%= rss_feed_link %>
|
||||
<%= text_feed_link %>
|
||||
All actions
|
||||
</li>
|
||||
<li>
|
||||
<%= rss_feed_link({ :due => 0 }) %>
|
||||
<%= text_feed_link({ :due => 0 }) %>
|
||||
Actions due today or earlier
|
||||
</li>
|
||||
<li>
|
||||
<%= rss_feed_link({ :due => 6 }) %>
|
||||
<%= text_feed_link({ :due => 6 }) %>
|
||||
Actions due in 7 days or earlier
|
||||
</li>
|
||||
<li><h4>Feeds for uncompleted actions in a specific context:</h4>
|
||||
<ul>
|
||||
<% for context in @contexts %>
|
||||
<li>
|
||||
<%= rss_feed_link({ :context => context }) %>
|
||||
<%= text_feed_link({ :context => context }) %>
|
||||
Next actions in <strong><%=h context.name %></strong>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h4>Feeds for uncompleted actions in a specific project:</h4>
|
||||
<ul>
|
||||
<% for project in @projects %>
|
||||
<li>
|
||||
<%= rss_feed_link({ :project => project }) %>
|
||||
<%= text_feed_link({ :project => project }) %>
|
||||
Next actions for <strong><%=h project.name %></strong>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div><!-- End of display_box -->
|
||||
|
||||
<div id="input_box">
|
||||
<%= render "shared/sidebar" %>
|
||||
</div><!-- End of input box -->
|
||||
|
|
@ -50,7 +50,7 @@ ActionController::Routing::Routes.draw do |map|
|
|||
map.connect 'notes', :controller => 'note', :action => 'index'
|
||||
|
||||
# Feed Routes
|
||||
map.connect 'feed/:action/:name/:user', :controller => 'feed'
|
||||
map.connect 'feed/:action/:name/:token', :controller => 'feed'
|
||||
|
||||
|
||||
#map.connect 'add_item', :controller => 'todo', :action => 'add_item'
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ Wiki (deprecated - please use Trac): http://www.rousette.org.uk/projects/wiki/
|
|||
19. There's a rake task (upgrade_sqlite_db) which allows you to safely upgrade databases created with version 1.03, afterwhich you can run rake migrate to complete the process. From there, rake migrate should work OK.
|
||||
20. Moved settings for Tracks from the file settings.yml to the database. Running 'rake migrate' will update your database appropriately, and add the default settings into it. Then you should be able to visit <tt>http://0.0.0.0:3000/user/preferences</tt> to view and edit your settings. The advantage is that you don't need to mess about with the settings.yml file, and each of the users can have their own settings.
|
||||
21. Session data is now stored in the database rather than a file in tracks/tmp. This should prevent the tmp directory cluttering up the file system, and give better performance. You need to run rake migrate to add the session table to your database.
|
||||
22. You can now change the password for the logged in user (user/preferences)
|
||||
23. Lots of new text and RSS feeds added by Luke Melia. These are accessed via the feed icon on in the main navigation.
|
||||
|
||||
== Version 1.03
|
||||
|
||||
|
|
|
|||
|
|
@ -579,4 +579,38 @@ div.message {
|
|||
list-style: disc;
|
||||
}
|
||||
|
||||
ul#prefs {list-style-type: disc; margin-left: 5px;}
|
||||
ul#prefs {list-style-type: disc; margin-left: 5px;}
|
||||
|
||||
#feedlegend {
|
||||
padding: 2px;
|
||||
border: 1px solid #CCC;
|
||||
background-color: #D2D3D6;
|
||||
color: #666;
|
||||
padding: 5px 20px;
|
||||
text-align: left;
|
||||
}
|
||||
#feedlegend h3, #feedlegend dl, #feedlegend dt, #feedlegend dd {
|
||||
display: inline;
|
||||
}
|
||||
#feedlegend dt {
|
||||
margin-left: 15px;
|
||||
}
|
||||
#feedlegend dd {
|
||||
margin-left: 3px;
|
||||
}
|
||||
#feedlegend p {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
#feeds img.rss-icon {
|
||||
margin-bottom: -4px;
|
||||
}
|
||||
#feeds li {
|
||||
font-size:13px;
|
||||
font-family: "Lucida Grande", Verdana, Geneva, Arial, sans-serif;
|
||||
}
|
||||
#feeds li h4 {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 4px;
|
||||
font-weight: normal;
|
||||
font-style:oblique;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue