taskwarrior-web 0.0.13 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +3 -0
- data/Guardfile +12 -0
- data/README.md +7 -6
- data/lib/taskwarrior-web/app.rb +13 -67
- data/lib/taskwarrior-web/command.rb +25 -0
- data/lib/taskwarrior-web/config.rb +16 -3
- data/lib/taskwarrior-web/helpers.rb +56 -0
- data/lib/taskwarrior-web/runner.rb +52 -3
- data/lib/taskwarrior-web/runners/v1.rb +11 -0
- data/lib/taskwarrior-web/runners/v2.rb +7 -0
- data/lib/taskwarrior-web/task.rb +23 -54
- data/public/js/application.js +7 -54
- data/spec/app/app_spec.rb +27 -0
- data/spec/app/helpers_spec.rb +36 -0
- data/spec/models/command_spec.rb +39 -0
- data/spec/models/runner_spec.rb +74 -0
- data/spec/models/task_spec.rb +81 -0
- data/spec/spec_helper.rb +18 -0
- data/taskwarrior-web.gemspec +5 -1
- data/views/listing.erb +3 -6
- metadata +75 -16
- data/Gemfile.lock +0 -42
data/.gitignore
CHANGED
data/.rspec
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## v0.0.14 (2/9/12)
|
2
|
+
|
3
|
+
* Merged in major refactoring to allow for easier support of task 2 and
|
4
|
+
1 simultaneously. Note that taskwarrior-web still only supports task 1, but
|
5
|
+
adding support for task 2 should now be easier.
|
6
|
+
* Removed the ability to mark a task as complete. This was really buggy to
|
7
|
+
begin with, and will need to wait until task 2.
|
8
|
+
* Fixed project autocomplete. Now it should actually work.
|
9
|
+
* Added a new tab for "Waiting" tasks (where status:waiting)
|
10
|
+
|
1
11
|
## v0.0.13 (2/6/12)
|
2
12
|
|
3
13
|
* Adding Fluid app dock icon. The dock icons should now show a number of
|
data/Gemfile
CHANGED
data/Guardfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'bundler' do
|
5
|
+
watch('Gemfile')
|
6
|
+
watch('taskwarrior-web.gemspec')
|
7
|
+
end
|
8
|
+
|
9
|
+
guard 'rspec', :version => 2 do
|
10
|
+
watch(/^lib\/(.+)\.rb$/) { "spec" }
|
11
|
+
watch(/^spec\/(.+)\.rb$/) { "spec" }
|
12
|
+
end
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Web Interface for Taskwarrior
|
1
|
+
# A Web Interface for Taskwarrior
|
2
2
|
|
3
3
|
A lightweight, Sinatra-based web interface for the
|
4
4
|
wonderful [Taskwarrior](http://taskwarrior.org/) todo application.
|
@@ -25,14 +25,18 @@ an executable, so all options for Vegas are valid for `task-web`. Type
|
|
25
25
|
The current featureset includes:
|
26
26
|
|
27
27
|
* Viewing tasks (duh) sorted and grouped in various ways.
|
28
|
-
* Marking a pending task as done.
|
29
28
|
* Creating a new task with a due date, project, and tags.
|
30
29
|
* `task-web` will pull your `task` config (from `.taskrc`) and use it to
|
31
30
|
determine date formatting and when an upcoming task should be marked as
|
32
31
|
"due".
|
32
|
+
* If you are on a Mac and use Fluid.app, you get a dock badge showing the
|
33
|
+
number of pending tasks.
|
33
34
|
|
34
35
|
I'm looking to include more features once `task` supports issuing commands via
|
35
|
-
UUID
|
36
|
+
UUID, like:
|
37
|
+
|
38
|
+
* Marking a pending task as done.
|
39
|
+
* Deleting tasks
|
36
40
|
|
37
41
|
## Known Issues
|
38
42
|
|
@@ -42,9 +46,6 @@ UUID.
|
|
42
46
|
Support for 1.8 will happen at some point.
|
43
47
|
* The "View as list"/"View as Grid" links do nothing right now. (They will
|
44
48
|
soon).
|
45
|
-
* There are occasionally pretty severe race conditions due to the way that
|
46
|
-
`task` assigns IDs to tasks. This will no longer be the case when UUIDs are
|
47
|
-
implemented in `task`.
|
48
49
|
|
49
50
|
## Marginalia
|
50
51
|
|
data/lib/taskwarrior-web/app.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'sinatra'
|
4
4
|
require 'erb'
|
5
|
-
require 'parseconfig'
|
6
|
-
require 'json'
|
7
5
|
require 'time'
|
8
6
|
require 'rinku'
|
7
|
+
require 'taskwarrior-web/config'
|
8
|
+
require 'taskwarrior-web/helpers'
|
9
9
|
require 'digest'
|
10
10
|
|
11
11
|
module TaskwarriorWeb
|
@@ -22,66 +22,18 @@ module TaskwarriorWeb
|
|
22
22
|
def authorized?
|
23
23
|
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
24
24
|
@auth.provided? && @auth.basic? && @auth.credentials &&
|
25
|
-
@auth.credentials[0] == TaskwarriorWeb::Config.
|
26
|
-
Digest::MD5.hexdigest(@auth.credentials[1]) == TaskwarriorWeb::Config.
|
25
|
+
@auth.credentials[0] == TaskwarriorWeb::Config.property('task-web.user') &&
|
26
|
+
Digest::MD5.hexdigest(@auth.credentials[1]) == TaskwarriorWeb::Config.property('task-web.passwd')
|
27
27
|
end
|
28
28
|
|
29
29
|
# Before filter
|
30
30
|
before do
|
31
31
|
@current_page = request.path_info
|
32
|
-
protected! if TaskwarriorWeb::Config.
|
32
|
+
protected! if TaskwarriorWeb::Config.property('task-web.user')
|
33
33
|
end
|
34
34
|
|
35
35
|
# Helpers
|
36
|
-
helpers
|
37
|
-
|
38
|
-
def format_date(timestamp)
|
39
|
-
format = TaskwarriorWeb::Config.file.get_value('dateformat') || 'm/d/Y'
|
40
|
-
subbed = format.gsub(/([a-zA-Z])/, '%\1')
|
41
|
-
Time.parse(timestamp).strftime(subbed)
|
42
|
-
end
|
43
|
-
|
44
|
-
def colorize_date(timestamp)
|
45
|
-
return if timestamp.nil?
|
46
|
-
due_def = TaskwarriorWeb::Config.file.get_value('due').to_i || 5
|
47
|
-
time = Time.parse(timestamp)
|
48
|
-
case true
|
49
|
-
when Time.now.strftime('%D') == time.strftime('%D') then 'today'
|
50
|
-
when Time.now.to_i > time.to_i then 'overdue'
|
51
|
-
when (time.to_i - Time.now.to_i) < (due_def * 86400) then 'due'
|
52
|
-
else 'regular'
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def linkify(item, method)
|
57
|
-
return if item.nil?
|
58
|
-
case method.to_s
|
59
|
-
when 'project'
|
60
|
-
item.downcase.gsub('.', '--')
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def auto_link(text)
|
65
|
-
Rinku.auto_link(text, :all, 'target="_blank"')
|
66
|
-
end
|
67
|
-
|
68
|
-
def subnav(type)
|
69
|
-
case type
|
70
|
-
when 'tasks' then
|
71
|
-
{ '/tasks/pending' => "Pending (#{TaskwarriorWeb::Task.count(:status => 'pending')})",
|
72
|
-
'/tasks/completed' => "Completed",
|
73
|
-
'/tasks/deleted' => 'Deleted'
|
74
|
-
}
|
75
|
-
when 'projects'
|
76
|
-
{
|
77
|
-
'/projects/overview' => 'Overview'
|
78
|
-
}
|
79
|
-
else
|
80
|
-
{ }
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
36
|
+
helpers TaskwarriorWeb::App::Helpers
|
85
37
|
|
86
38
|
# Redirects
|
87
39
|
get '/' do
|
@@ -93,7 +45,7 @@ module TaskwarriorWeb
|
|
93
45
|
|
94
46
|
# Task routes
|
95
47
|
get '/tasks/:status/?' do
|
96
|
-
pass unless ['pending', 'completed', 'deleted'].include?(params[:status])
|
48
|
+
pass unless ['pending', 'waiting', 'completed', 'deleted'].include?(params[:status])
|
97
49
|
@title = "#{params[:status].capitalize} Tasks"
|
98
50
|
@subnav = subnav('tasks')
|
99
51
|
@tasks = TaskwarriorWeb::Task.find_by_status(params[:status]).sort_by! { |x| [x.priority.nil?.to_s, x.priority.to_s, x.due.nil?.to_s, x.due.to_s, x.project.to_s] }
|
@@ -103,7 +55,7 @@ module TaskwarriorWeb
|
|
103
55
|
get '/tasks/new/?' do
|
104
56
|
@title = 'New Task'
|
105
57
|
@subnav = subnav('tasks')
|
106
|
-
@date_format = TaskwarriorWeb::Config.
|
58
|
+
@date_format = TaskwarriorWeb::Config.dateformat || 'm/d/yy'
|
107
59
|
@date_format.gsub!('Y', 'yy')
|
108
60
|
erb :task_form
|
109
61
|
end
|
@@ -124,11 +76,6 @@ module TaskwarriorWeb
|
|
124
76
|
end
|
125
77
|
end
|
126
78
|
|
127
|
-
post '/tasks/:id/complete' do
|
128
|
-
TaskwarriorWeb::Task.complete!(params[:id])
|
129
|
-
redirect '/tasks/pending'
|
130
|
-
end
|
131
|
-
|
132
79
|
# Projects
|
133
80
|
get '/projects' do
|
134
81
|
redirect '/projects/overview'
|
@@ -144,9 +91,8 @@ module TaskwarriorWeb
|
|
144
91
|
get '/projects/:name/?' do
|
145
92
|
@subnav = subnav('projects')
|
146
93
|
subbed = params[:name].gsub('--', '.')
|
147
|
-
@tasks = TaskwarriorWeb::Task.query('status.not' => 'deleted',
|
148
|
-
|
149
|
-
@title = @tasks.select { |t| t.project.match(regex) }.first.project
|
94
|
+
@tasks = TaskwarriorWeb::Task.query('status.not' => 'deleted', :project => subbed).sort_by! { |x| [x.priority.nil?.to_s, x.priority.to_s, x.due.nil?.to_s, x.due.to_s] }
|
95
|
+
@title = @tasks.select { |t| t.project.match(/^#{subbed}$/i) }.first.project
|
150
96
|
erb :project
|
151
97
|
end
|
152
98
|
|
@@ -157,7 +103,7 @@ module TaskwarriorWeb
|
|
157
103
|
# AJAX callbacks
|
158
104
|
get '/ajax/projects/?' do
|
159
105
|
projects = TaskwarriorWeb::Task.query('status.not' => 'deleted').collect { |t| t.project }
|
160
|
-
projects.compact
|
106
|
+
projects.compact.uniq.select {|proj| proj.start_with?(params[:term]) }.to_json
|
161
107
|
end
|
162
108
|
|
163
109
|
get '/ajax/tags/?' do
|
@@ -181,8 +127,8 @@ module TaskwarriorWeb
|
|
181
127
|
|
182
128
|
def passes_validation(item, method)
|
183
129
|
results = []
|
184
|
-
case method
|
185
|
-
when
|
130
|
+
case method
|
131
|
+
when :task
|
186
132
|
if item['description'].empty?
|
187
133
|
results << 'You must provide a description'
|
188
134
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'taskwarrior-web/runner'
|
2
|
+
|
3
|
+
module TaskwarriorWeb
|
4
|
+
class Command
|
5
|
+
|
6
|
+
attr_accessor :command, :id, :params
|
7
|
+
|
8
|
+
def initialize(command, id = nil, *args)
|
9
|
+
@command = command if command
|
10
|
+
@id = id if id
|
11
|
+
@params = args.last.is_a?(::Hash) ? args.pop : {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
if @command
|
16
|
+
TaskwarriorWeb::Runner.run(self)
|
17
|
+
else
|
18
|
+
raise MissingCommandError
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class MissingCommandError < Exception; end
|
25
|
+
end
|
@@ -1,11 +1,24 @@
|
|
1
|
+
require 'parseconfig'
|
2
|
+
|
1
3
|
module TaskwarriorWeb
|
2
|
-
|
4
|
+
class Config
|
3
5
|
|
4
|
-
|
6
|
+
def self.task_version
|
7
|
+
# TODO: Parse the actual task version
|
8
|
+
1
|
9
|
+
end
|
5
10
|
|
6
|
-
def file
|
11
|
+
def self.file
|
7
12
|
@file ||= ParseConfig.new("#{Dir.home}/.taskrc")
|
8
13
|
end
|
9
14
|
|
15
|
+
def self.property(prop)
|
16
|
+
self.file.get_value(prop)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.method_missing(method)
|
20
|
+
self.file.get_value(method)
|
21
|
+
end
|
22
|
+
|
10
23
|
end
|
11
24
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'taskwarrior-web/config'
|
2
|
+
|
3
|
+
module TaskwarriorWeb
|
4
|
+
class App < Sinatra::Base
|
5
|
+
module Helpers
|
6
|
+
|
7
|
+
def format_date(timestamp)
|
8
|
+
format = TaskwarriorWeb::Config.dateformat || 'm/d/Y'
|
9
|
+
subbed = format.gsub(/([a-zA-Z])/, '%\1')
|
10
|
+
Time.parse(timestamp).strftime(subbed)
|
11
|
+
end
|
12
|
+
|
13
|
+
def colorize_date(timestamp)
|
14
|
+
return if timestamp.nil?
|
15
|
+
due_def = TaskwarriorWeb::Config.due.to_i || 5
|
16
|
+
time = Time.parse(timestamp)
|
17
|
+
case true
|
18
|
+
when Time.now.strftime('%D') == time.strftime('%D') then 'today'
|
19
|
+
when Time.now.to_i > time.to_i then 'overdue'
|
20
|
+
when (time.to_i - Time.now.to_i) < (due_def * 86400) then 'due'
|
21
|
+
else 'regular'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def linkify(item, method)
|
26
|
+
return if item.nil?
|
27
|
+
case method.to_s
|
28
|
+
when 'project'
|
29
|
+
item.downcase.gsub('.', '--')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def auto_link(text)
|
34
|
+
Rinku.auto_link(text, :all, 'target="_blank"')
|
35
|
+
end
|
36
|
+
|
37
|
+
def subnav(type)
|
38
|
+
case type
|
39
|
+
when 'tasks' then
|
40
|
+
{ '/tasks/pending' => "Pending (#{TaskwarriorWeb::Task.count(:status => :pending)})",
|
41
|
+
'/tasks/waiting' => "Waiting",
|
42
|
+
'/tasks/completed' => "Completed",
|
43
|
+
'/tasks/deleted' => 'Deleted'
|
44
|
+
}
|
45
|
+
when 'projects'
|
46
|
+
{
|
47
|
+
'/projects/overview' => 'Overview'
|
48
|
+
}
|
49
|
+
else
|
50
|
+
{ }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,12 +1,61 @@
|
|
1
|
+
require 'taskwarrior-web/config'
|
2
|
+
|
1
3
|
module TaskwarriorWeb
|
2
4
|
class Runner
|
3
5
|
|
4
6
|
TASK_BIN = 'task'
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
TASK_COMMANDS = {
|
9
|
+
:add => 'add',
|
10
|
+
:query => '_query',
|
11
|
+
:count => 'count'
|
12
|
+
}
|
13
|
+
|
14
|
+
def self.run(command_obj)
|
15
|
+
command = build(command_obj)
|
16
|
+
# Add some logging
|
17
|
+
`#{TASK_BIN} #{command}`
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.build(command_obj)
|
21
|
+
command = task_command(command_obj)
|
22
|
+
command = substitute_parts(command, command_obj) if command =~ /:id/
|
23
|
+
params = parsed_params(command_obj.params)
|
24
|
+
"#{command}#{params}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.task_command(command_obj)
|
28
|
+
if TASK_COMMANDS.has_key?(command_obj.command.to_sym)
|
29
|
+
TASK_COMMANDS[command_obj.command.to_sym]
|
30
|
+
else
|
31
|
+
raise InvalidCommandError
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.substitute_parts(task_command, command_obj)
|
36
|
+
if command_obj.id
|
37
|
+
task_command.gsub(':id', command_obj.id.to_s)
|
38
|
+
else
|
39
|
+
raise MissingTaskIDError
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.parsed_params(params)
|
44
|
+
String.new.tap do |string|
|
45
|
+
string << " '#{params.delete(:description)}'" if params.has_key?(:description)
|
46
|
+
|
47
|
+
if params.has_key?(:tags)
|
48
|
+
tags = params.delete(:tags)
|
49
|
+
tag_indicator = TaskwarriorWeb::Config.property('tag.indicator') || '+'
|
50
|
+
tags.each { |tag| string << " #{tag_indicator}#{tag.to_s}" }
|
51
|
+
end
|
52
|
+
|
53
|
+
params.each { |attr, value| string << " #{attr.to_s}:#{value.to_s}" }
|
54
|
+
end
|
9
55
|
end
|
10
56
|
|
11
57
|
end
|
58
|
+
|
59
|
+
class InvalidCommandError < Exception; end
|
60
|
+
class MissingTaskIDError < Exception; end
|
12
61
|
end
|
data/lib/taskwarrior-web/task.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
require '
|
1
|
+
require 'json'
|
2
|
+
require 'taskwarrior-web/command'
|
2
3
|
|
3
4
|
module TaskwarriorWeb
|
4
5
|
|
@@ -7,7 +8,7 @@ module TaskwarriorWeb
|
|
7
8
|
#################
|
8
9
|
class Task
|
9
10
|
|
10
|
-
attr_accessor :
|
11
|
+
attr_accessor :entry, :project, :priority, :uuid, :description, :status,
|
11
12
|
:due, :start, :end, :tags, :depends, :wait, :annotations
|
12
13
|
alias :annotate= :annotations=
|
13
14
|
|
@@ -22,19 +23,16 @@ module TaskwarriorWeb
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def save!
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
end
|
37
|
-
TaskwarriorWeb::Runner.run(command)
|
26
|
+
Command.new(:add, nil, self.to_hash).run
|
27
|
+
end
|
28
|
+
|
29
|
+
# Make sure that the tags are an array.
|
30
|
+
def tags=(value)
|
31
|
+
@tags = value.is_a?(String) ? value.gsub(', ', ',').split(',') : value
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_hash
|
35
|
+
Hash[instance_variables.map { |var| [var[1..-1].to_sym, instance_variable_get(var)] }]
|
38
36
|
end
|
39
37
|
|
40
38
|
##################################
|
@@ -44,34 +42,27 @@ module TaskwarriorWeb
|
|
44
42
|
# Run queries on tasks.
|
45
43
|
def self.query(*args)
|
46
44
|
tasks = []
|
47
|
-
count = 1
|
48
|
-
|
49
|
-
command = '_query'
|
50
|
-
args.each do |param|
|
51
|
-
param.each do |attr, value|
|
52
|
-
command << " #{attr.to_s}:#{value}"
|
53
|
-
end
|
54
|
-
end
|
55
45
|
|
56
46
|
# Process the JSON data.
|
57
|
-
json =
|
47
|
+
json = Command.new(:query, nil, *args).run
|
58
48
|
json.strip!
|
59
49
|
json = '[' + json + ']'
|
60
|
-
results = json == '[No matches.]' ? [] : JSON.parse(json)
|
50
|
+
results = json == '[No matches.]' ? [] : ::JSON.parse(json)
|
61
51
|
|
62
|
-
results.each
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
52
|
+
results.each { |result| tasks << Task.new(result) }
|
53
|
+
tasks
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get the number of tasks for some paramters
|
57
|
+
def self.count(*args)
|
58
|
+
Command.new(:count, nil, *args).run.to_s.strip!
|
68
59
|
end
|
69
60
|
|
70
61
|
# Define method_missing to implement dynamic finder methods
|
71
62
|
def self.method_missing(method_sym, *arguments, &block)
|
72
63
|
match = TaskDynamicFinderMatch.new(method_sym)
|
73
64
|
if match.match?
|
74
|
-
self.query(match.attribute => arguments.first)
|
65
|
+
self.query(match.attribute.to_s => arguments.first.to_s)
|
75
66
|
else
|
76
67
|
super
|
77
68
|
end
|
@@ -86,28 +77,6 @@ module TaskwarriorWeb
|
|
86
77
|
end
|
87
78
|
end
|
88
79
|
|
89
|
-
# Get the number of tasks for some paramters
|
90
|
-
def self.count(*args)
|
91
|
-
command = 'count'
|
92
|
-
args.each do |param|
|
93
|
-
param.each do |attr, value|
|
94
|
-
command << " #{attr.to_s}:#{value}"
|
95
|
-
end
|
96
|
-
end
|
97
|
-
return TaskwarriorWeb::Runner.run(command).strip!
|
98
|
-
end
|
99
|
-
|
100
|
-
###############################################
|
101
|
-
# CLASS METHODS FOR INTERACTING WITH TASKS
|
102
|
-
# (THESE WILL PROBABLY BECOME INSTANCE METHODS)
|
103
|
-
###############################################
|
104
|
-
|
105
|
-
# Mark a task as complete
|
106
|
-
# TODO: Make into instance method when `task` supports finding by UUID.
|
107
|
-
def self.complete!(task_id)
|
108
|
-
TaskwarriorWeb::Runner.run("#{task_id} done")
|
109
|
-
end
|
110
|
-
|
111
80
|
end
|
112
81
|
|
113
82
|
###########################################
|
data/public/js/application.js
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
$(document).ready(function() {
|
2
2
|
initPolling();
|
3
3
|
initTooltips();
|
4
|
-
initCompleteTask();
|
5
4
|
initDatePicker();
|
6
5
|
initAutocomplete();
|
7
|
-
|
6
|
+
|
7
|
+
// Fluid-specific stuff.
|
8
|
+
if (window.fluid) {
|
9
|
+
refreshDockBadge();
|
10
|
+
}
|
8
11
|
});
|
9
12
|
|
10
13
|
var initPolling = function() {
|
11
|
-
var polling;
|
12
|
-
if (polling
|
14
|
+
var polling = $.cookie('taskwarrior-web-polling');
|
15
|
+
if (polling) {
|
13
16
|
var pollingInterval = startPolling();
|
14
17
|
} else {
|
15
18
|
$('#polling-info a').text('Start polling');
|
@@ -54,56 +57,6 @@ var initTooltips = function() {
|
|
54
57
|
});
|
55
58
|
};
|
56
59
|
|
57
|
-
var initCompleteTask = function() {
|
58
|
-
$('input.pending').live('change', function() {
|
59
|
-
var checkbox = $(this);
|
60
|
-
var row = checkbox.closest('tr');
|
61
|
-
var task_id = $(this).data('task');
|
62
|
-
$.ajax({
|
63
|
-
url: '/tasks/' + task_id + '/complete',
|
64
|
-
type: 'post',
|
65
|
-
beforeSend: function() {
|
66
|
-
checkbox.replaceWith('<img src="/images/ajax-loader.gif" />');
|
67
|
-
},
|
68
|
-
success: function(data) {
|
69
|
-
row.fadeOut('slow', function() {
|
70
|
-
row.remove();
|
71
|
-
refreshSubnavCount();
|
72
|
-
refreshDockBadge();
|
73
|
-
});
|
74
|
-
}
|
75
|
-
});
|
76
|
-
});
|
77
|
-
};
|
78
|
-
|
79
|
-
var initInPlaceEditing = function() {
|
80
|
-
// Hide it initially.
|
81
|
-
$('.inplace-edit').hide();
|
82
|
-
$('#listing table td').live('mouseover mouseout', function(e) {
|
83
|
-
if (e.type == 'mouseover') {
|
84
|
-
$('.inplace-edit', this).show();
|
85
|
-
} else {
|
86
|
-
$('.inplace-edit', this).hide();
|
87
|
-
}
|
88
|
-
});
|
89
|
-
|
90
|
-
$('.inplace-edit').live('click', function() {
|
91
|
-
var field = $($(this).siblings('span')[0]);
|
92
|
-
var formElement = '<input type="text" class="inplace-text" value="'+field.text()+'" />';
|
93
|
-
formElement += '<button type="submit" class="inplace-submit">Update</button>';
|
94
|
-
formElement += '<a href="javascript:void(0);" class="inplace-cancel">Cancel</a>';
|
95
|
-
field.replaceWith(formElement);
|
96
|
-
$(this).remove();
|
97
|
-
});
|
98
|
-
|
99
|
-
$('.inplace-cancel').live('click', function() {
|
100
|
-
var td = $(this).closest('td');
|
101
|
-
var oldField = '<span class="description">'+$($(this).siblings('.inplace-text')[0]).val()+'</span>';
|
102
|
-
oldField += '<a class="inplace-edit" href="javascript:void(0);">Edit</a>';
|
103
|
-
td.html(oldField);
|
104
|
-
});
|
105
|
-
};
|
106
|
-
|
107
60
|
var initDatePicker = function() {
|
108
61
|
$('.datefield input').datepicker({
|
109
62
|
dateFormat: $('.datefield input').data('format'),
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'taskwarrior-web/app'
|
3
|
+
|
4
|
+
set :environment, :test
|
5
|
+
|
6
|
+
describe "My App" do
|
7
|
+
include Rack::Test::Methods
|
8
|
+
|
9
|
+
def app
|
10
|
+
TaskwarriorWeb::App
|
11
|
+
end
|
12
|
+
|
13
|
+
before do
|
14
|
+
TaskwarriorWeb::Config.should_receive(:property).with('task-web.user').any_number_of_times.and_return(nil)
|
15
|
+
TaskwarriorWeb::Runner.should_receive(:run).any_number_of_times.and_return('{}')
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'GET /' do
|
19
|
+
it 'should redirect to /tasks/pending' do
|
20
|
+
get "/"
|
21
|
+
follow_redirect!
|
22
|
+
|
23
|
+
last_request.url.should =~ /tasks\/pending/
|
24
|
+
last_response.should be_ok
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'taskwarrior-web/helpers'
|
3
|
+
|
4
|
+
class TestHelpers
|
5
|
+
include TaskwarriorWeb::App::Helpers
|
6
|
+
end
|
7
|
+
|
8
|
+
describe TaskwarriorWeb::App::Helpers do
|
9
|
+
let(:helpers) { TestHelpers.new }
|
10
|
+
|
11
|
+
describe '#format_date' do
|
12
|
+
context 'with no format specified' do
|
13
|
+
before do
|
14
|
+
TaskwarriorWeb::Config.should_receive(:dateformat).any_number_of_times.and_return(nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should format various dates and times to the default format' do
|
18
|
+
helpers.format_date('2012-01-11 12:23:00').should == '01/11/2012'
|
19
|
+
helpers.format_date('2012-01-11').should == '01/11/2012'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with a specified date format' do
|
24
|
+
before do
|
25
|
+
TaskwarriorWeb::Config.should_receive(:dateformat).any_number_of_times.and_return('d/m/Y')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should format dates using the specified format' do
|
29
|
+
helpers.format_date('2012-01-11 12:23:00').should == '11/01/2012'
|
30
|
+
helpers.format_date('2012-01-11').should == '11/01/2012'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'taskwarrior-web/command'
|
3
|
+
|
4
|
+
describe TaskwarriorWeb::Command do
|
5
|
+
describe '.initialize' do
|
6
|
+
context 'when the command, id, and params are specified' do
|
7
|
+
it 'should set the passed variables' do
|
8
|
+
command = TaskwarriorWeb::Command.new('test', 3, :hello => :hi, :none => :none)
|
9
|
+
command.command.should eq('test')
|
10
|
+
command.id.should eq(3)
|
11
|
+
command.params.should eq({ :hello => :hi, :none => :none })
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should not set an @id if none is passed' do
|
16
|
+
command = TaskwarriorWeb::Command.new('test', nil, :hello => :hi, :none => :none)
|
17
|
+
command.command.should eq('test')
|
18
|
+
command.id.should be_nil
|
19
|
+
command.params.should eq({ :hello => :hi, :none => :none })
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#run' do
|
24
|
+
before do
|
25
|
+
@command = TaskwarriorWeb::Command.new('test', 4)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should pass the object to the Runner' do
|
29
|
+
TaskwarriorWeb::Runner.should_receive(:run).with(@command).and_return('{}')
|
30
|
+
@command.run
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should raise an exception if no command is specified' do
|
34
|
+
command = TaskwarriorWeb::Command.new(nil, 5)
|
35
|
+
expect { command.run }.to raise_error(TaskwarriorWeb::MissingCommandError)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'taskwarrior-web/runner'
|
3
|
+
|
4
|
+
describe TaskwarriorWeb::Runner do
|
5
|
+
before do
|
6
|
+
@command = TaskwarriorWeb::Command.new(:add)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '.run' do
|
10
|
+
context 'valid, without a command' do
|
11
|
+
before do
|
12
|
+
TaskwarriorWeb::Runner.should_receive(:`).and_return('{}')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should return the stdout' do
|
16
|
+
TaskwarriorWeb::Runner.run(@command).should eq('{}')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should not call .substitute_parts if not necessary' do
|
20
|
+
TaskwarriorWeb::Runner.should_not_receive(:substitute_parts)
|
21
|
+
TaskwarriorWeb::Runner.run(@command)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'invalid' do
|
26
|
+
it 'should throw an exception if the command is not valid' do
|
27
|
+
@command.command = :test
|
28
|
+
expect { TaskwarriorWeb::Runner.run(@command) }.to raise_error(TaskwarriorWeb::InvalidCommandError)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with a given command' do
|
33
|
+
it 'should execute the given command' do
|
34
|
+
TaskwarriorWeb::Runner.should_receive(:`).with('task add').and_return('{}')
|
35
|
+
TaskwarriorWeb::Runner.run(@command)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '.substitute_parts' do
|
41
|
+
it 'should replace the :id string with the given task ID' do
|
42
|
+
command = TaskwarriorWeb::Command.new(:complete, 4)
|
43
|
+
TaskwarriorWeb::Runner.substitute_parts(':id done', command).should eq('4 done')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should throw an error if the command has no task ID' do
|
47
|
+
expect { TaskwarriorWeb::Runner.substitute_parts(':id done', @command) }.to raise_error(TaskwarriorWeb::MissingTaskIDError)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '.parsed_params' do
|
52
|
+
it 'should create a string from the passed paramters' do
|
53
|
+
command = TaskwarriorWeb::Command.new(:query, nil, :test => 14, :none => :none, :hello => :hi)
|
54
|
+
TaskwarriorWeb::Runner.parsed_params(command.params).should eq(' test:14 none:none hello:hi')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should prefix tags with the tag.indicator if specified' do
|
58
|
+
TaskwarriorWeb::Config.should_receive(:property).with('tag.indicator').and_return(';')
|
59
|
+
command = TaskwarriorWeb::Command.new(:add, nil, :tags => [:today, :tomorrow])
|
60
|
+
TaskwarriorWeb::Runner.parsed_params(command.params).should eq(' ;today ;tomorrow')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should prefix tags with a + if no tag.indicator is specified' do
|
64
|
+
TaskwarriorWeb::Config.should_receive(:property).with('tag.indicator').and_return(nil)
|
65
|
+
command = TaskwarriorWeb::Command.new(:add, nil, :tags => [:today, :tomorrow])
|
66
|
+
TaskwarriorWeb::Runner.parsed_params(command.params).should eq(' +today +tomorrow')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should pull out the description parameter' do
|
70
|
+
command = TaskwarriorWeb::Command.new(:add, nil, :description => 'Hello', :status => :pending)
|
71
|
+
TaskwarriorWeb::Runner.parsed_params(command.params).should eq(" 'Hello' status:pending")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/spec/models/task_spec.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
1
2
|
require 'taskwarrior-web/task'
|
2
3
|
|
3
4
|
describe TaskwarriorWeb::Task do
|
5
|
+
RSpec::Mocks::setup(TaskwarriorWeb::Runner)
|
6
|
+
TaskwarriorWeb::Runner.stub(:run) { '{}' }
|
4
7
|
|
5
8
|
describe '#initialize' do
|
6
9
|
it 'should assign the passed attributes' do
|
@@ -14,4 +17,82 @@ describe TaskwarriorWeb::Task do
|
|
14
17
|
task.respond_to?(:bogus).should be_false
|
15
18
|
end
|
16
19
|
end
|
20
|
+
|
21
|
+
describe '.query' do
|
22
|
+
it 'should create and run a new Command object' do
|
23
|
+
command = TaskwarriorWeb::Command.new(:query)
|
24
|
+
TaskwarriorWeb::Command.should_receive(:new).with(:query, nil).and_return(command)
|
25
|
+
command.should_receive(:run).and_return('{}')
|
26
|
+
TaskwarriorWeb::Task.query
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should parse the JSON received from the `task` command' do
|
30
|
+
TaskwarriorWeb::Runner.should_receive(:run).and_return('{}')
|
31
|
+
::JSON.should_receive(:parse).with('[{}]').and_return([])
|
32
|
+
TaskwarriorWeb::Task.query
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should not parse the results when there are no matching tasks' do
|
36
|
+
TaskwarriorWeb::Runner.should_receive(:run).and_return('No matches.')
|
37
|
+
::JSON.should_not_receive(:parse)
|
38
|
+
TaskwarriorWeb::Task.query
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '.count' do
|
43
|
+
it 'create and run an new command object' do
|
44
|
+
command = TaskwarriorWeb::Command.new(:count)
|
45
|
+
TaskwarriorWeb::Command.should_receive(:new).with(:count, nil).and_return(command)
|
46
|
+
command.should_receive(:run).and_return('{}')
|
47
|
+
TaskwarriorWeb::Task.count
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#tags=' do
|
52
|
+
it 'should convert a string to an array when initializing' do
|
53
|
+
task = TaskwarriorWeb::Task.new(:tags => 'hi there, twice')
|
54
|
+
task.tags.should eq(['hi there', 'twice'])
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should convert a string to an array when setting explicitly' do
|
58
|
+
task = TaskwarriorWeb::Task.new
|
59
|
+
task.tags = 'hello, twice,thrice'
|
60
|
+
task.tags.should eq(['hello', 'twice', 'thrice'])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#to_hash' do
|
65
|
+
before do
|
66
|
+
@task = TaskwarriorWeb::Task.new(:description => 'Testing', :due => '12/2/12', :tags => 'hello, twice')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should return a hash' do
|
70
|
+
@task.to_hash.should be_a(Hash)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should have keys for each of the object\'s instance variables' do
|
74
|
+
@task.to_hash.should eq({:description => 'Testing', :due => '12/2/12', :tags => ['hello', 'twice']})
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '.method_missing' do
|
79
|
+
it 'should call the query method for find_by queries' do
|
80
|
+
TaskwarriorWeb::Task.should_receive(:query).with('status' => 'pending')
|
81
|
+
TaskwarriorWeb::Task.find_by_status(:pending)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should call pass other methods to super if not find_by_*' do
|
85
|
+
TaskwarriorWeb::Task.should_not_receive(:query)
|
86
|
+
Object.should_receive(:method_missing).with(:do_a_thing, anything)
|
87
|
+
TaskwarriorWeb::Task.do_a_thing(:pending)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should make the class respond to find_by queries' do
|
91
|
+
TaskwarriorWeb::Task.should respond_to(:find_by_test)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should not add support for obviously bogus methods' do
|
95
|
+
TaskwarriorWeb::Task.should_not respond_to(:wefiohhohiihihih)
|
96
|
+
end
|
97
|
+
end
|
17
98
|
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'rspec'
|
4
|
+
|
5
|
+
# Simplecov
|
6
|
+
require 'simplecov'
|
7
|
+
SimpleCov.start do
|
8
|
+
add_filter "spec"
|
9
|
+
end
|
10
|
+
|
11
|
+
# Requires supporting files with custom matchers and macros, etc,
|
12
|
+
# in ./support/ and its subdirectories.
|
13
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.mock_with :rspec
|
17
|
+
config.include(RSpec::Mocks::Methods)
|
18
|
+
end
|
data/taskwarrior-web.gemspec
CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "taskwarrior-web"
|
6
|
-
s.version = '0.0.
|
6
|
+
s.version = '0.0.14'
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
8
|
s.authors = ["Jake Bell"]
|
9
9
|
s.email = ["jake@theunraveler.com"]
|
@@ -21,7 +21,11 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_dependency('rinku')
|
22
22
|
|
23
23
|
s.add_development_dependency('rake')
|
24
|
+
s.add_development_dependency('rack-test')
|
24
25
|
s.add_development_dependency('rspec')
|
26
|
+
s.add_development_dependency('simplecov')
|
27
|
+
s.add_development_dependency('guard-rspec')
|
28
|
+
s.add_development_dependency('guard-bundler')
|
25
29
|
|
26
30
|
s.files = `git ls-files`.split("\n")
|
27
31
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/views/listing.erb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
<table>
|
3
3
|
<thead>
|
4
4
|
<tr>
|
5
|
-
<th></th>
|
6
5
|
<th>Description</th>
|
7
6
|
<th>Project</th>
|
8
7
|
<th>Due</th>
|
@@ -14,11 +13,9 @@
|
|
14
13
|
<% @tasks.each do |task| %>
|
15
14
|
<% if task.status == 'pending' %>
|
16
15
|
<tr class="<%= colorize_date(task.due) %>">
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
<td></td>
|
21
|
-
<% end %>
|
16
|
+
<% else %>
|
17
|
+
<tr class="<%= task.status %>">
|
18
|
+
<% end %>
|
22
19
|
<td>
|
23
20
|
<%= task.description %>
|
24
21
|
<% unless task.annotations.nil? || task.annotations.empty? %>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: taskwarrior-web
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.14
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sinatra
|
16
|
-
requirement: &
|
16
|
+
requirement: &2152168480 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2152168480
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: parseconfig
|
27
|
-
requirement: &
|
27
|
+
requirement: &2152167760 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2152167760
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: vegas
|
38
|
-
requirement: &
|
38
|
+
requirement: &2152167020 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2152167020
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rinku
|
49
|
-
requirement: &
|
49
|
+
requirement: &2152166160 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2152166160
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rake
|
60
|
-
requirement: &
|
60
|
+
requirement: &2152165600 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,54 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *2152165600
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rack-test
|
71
|
+
requirement: &2152165000 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *2152165000
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: rspec
|
71
|
-
requirement: &
|
82
|
+
requirement: &2152164380 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *2152164380
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: simplecov
|
93
|
+
requirement: &2152023060 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *2152023060
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: guard-rspec
|
104
|
+
requirement: &2152021400 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *2152021400
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: guard-bundler
|
115
|
+
requirement: &2152020560 !ruby/object:Gem::Requirement
|
72
116
|
none: false
|
73
117
|
requirements:
|
74
118
|
- - ! '>='
|
@@ -76,7 +120,7 @@ dependencies:
|
|
76
120
|
version: '0'
|
77
121
|
type: :development
|
78
122
|
prerelease: false
|
79
|
-
version_requirements: *
|
123
|
+
version_requirements: *2152020560
|
80
124
|
description: This gem provides a graphical frontend for the Taskwarrior task manager.
|
81
125
|
It is based on Sinatra.
|
82
126
|
email:
|
@@ -87,18 +131,23 @@ extensions: []
|
|
87
131
|
extra_rdoc_files: []
|
88
132
|
files:
|
89
133
|
- .gitignore
|
134
|
+
- .rspec
|
90
135
|
- .travis.yml
|
91
136
|
- CHANGELOG.md
|
92
137
|
- Gemfile
|
93
|
-
-
|
138
|
+
- Guardfile
|
94
139
|
- README.md
|
95
140
|
- Rakefile
|
96
141
|
- bin/task-web
|
97
142
|
- config.ru
|
98
143
|
- lib/taskwarrior-web.rb
|
99
144
|
- lib/taskwarrior-web/app.rb
|
145
|
+
- lib/taskwarrior-web/command.rb
|
100
146
|
- lib/taskwarrior-web/config.rb
|
147
|
+
- lib/taskwarrior-web/helpers.rb
|
101
148
|
- lib/taskwarrior-web/runner.rb
|
149
|
+
- lib/taskwarrior-web/runners/v1.rb
|
150
|
+
- lib/taskwarrior-web/runners/v2.rb
|
102
151
|
- lib/taskwarrior-web/task.rb
|
103
152
|
- public/css/gh-buttons.css
|
104
153
|
- public/css/jquery-ui.css
|
@@ -128,7 +177,12 @@ files:
|
|
128
177
|
- public/js/jquery.min.js
|
129
178
|
- public/js/jquery.tagsinput.js
|
130
179
|
- public/js/jquery.tipsy.js
|
180
|
+
- spec/app/app_spec.rb
|
181
|
+
- spec/app/helpers_spec.rb
|
182
|
+
- spec/models/command_spec.rb
|
183
|
+
- spec/models/runner_spec.rb
|
131
184
|
- spec/models/task_spec.rb
|
185
|
+
- spec/spec_helper.rb
|
132
186
|
- taskwarrior-web.gemspec
|
133
187
|
- views/404.erb
|
134
188
|
- views/_navigation.erb
|
@@ -157,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
211
|
version: '0'
|
158
212
|
segments:
|
159
213
|
- 0
|
160
|
-
hash: -
|
214
|
+
hash: -1565305535582289311
|
161
215
|
requirements: []
|
162
216
|
rubyforge_project: taskwarrior-web
|
163
217
|
rubygems_version: 1.8.11
|
@@ -165,4 +219,9 @@ signing_key:
|
|
165
219
|
specification_version: 3
|
166
220
|
summary: Web frontend for taskwarrior command line task manager.
|
167
221
|
test_files:
|
222
|
+
- spec/app/app_spec.rb
|
223
|
+
- spec/app/helpers_spec.rb
|
224
|
+
- spec/models/command_spec.rb
|
225
|
+
- spec/models/runner_spec.rb
|
168
226
|
- spec/models/task_spec.rb
|
227
|
+
- spec/spec_helper.rb
|
data/Gemfile.lock
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
taskwarrior-web (0.0.13)
|
5
|
-
parseconfig
|
6
|
-
rinku
|
7
|
-
sinatra
|
8
|
-
vegas
|
9
|
-
|
10
|
-
GEM
|
11
|
-
remote: http://rubygems.org/
|
12
|
-
specs:
|
13
|
-
diff-lcs (1.1.3)
|
14
|
-
parseconfig (0.5.2)
|
15
|
-
rack (1.4.1)
|
16
|
-
rack-protection (1.2.0)
|
17
|
-
rack
|
18
|
-
rake (0.9.2.2)
|
19
|
-
rinku (1.5.0)
|
20
|
-
rspec (2.8.0)
|
21
|
-
rspec-core (~> 2.8.0)
|
22
|
-
rspec-expectations (~> 2.8.0)
|
23
|
-
rspec-mocks (~> 2.8.0)
|
24
|
-
rspec-core (2.8.0)
|
25
|
-
rspec-expectations (2.8.0)
|
26
|
-
diff-lcs (~> 1.1.2)
|
27
|
-
rspec-mocks (2.8.0)
|
28
|
-
sinatra (1.3.2)
|
29
|
-
rack (~> 1.3, >= 1.3.6)
|
30
|
-
rack-protection (~> 1.2)
|
31
|
-
tilt (~> 1.3, >= 1.3.3)
|
32
|
-
tilt (1.3.3)
|
33
|
-
vegas (0.1.11)
|
34
|
-
rack (>= 1.0.0)
|
35
|
-
|
36
|
-
PLATFORMS
|
37
|
-
ruby
|
38
|
-
|
39
|
-
DEPENDENCIES
|
40
|
-
rake
|
41
|
-
rspec
|
42
|
-
taskwarrior-web!
|