taskwarrior-web 0.0.13 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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!
|