taskwarrior-web 1.0.14 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +2 -1
- data/CHANGELOG.md +7 -0
- data/README.md +2 -5
- data/lib/taskwarrior-web.rb +1 -0
- data/lib/taskwarrior-web/app.rb +59 -49
- data/lib/taskwarrior-web/config/navigation.rb +1 -1
- data/lib/taskwarrior-web/helpers.rb +40 -3
- data/lib/taskwarrior-web/model/config.rb +8 -1
- data/lib/taskwarrior-web/model/task.rb +10 -2
- data/lib/taskwarrior-web/public/js/application.js +4 -2
- data/lib/taskwarrior-web/services/builder/base.rb +7 -1
- data/lib/taskwarrior-web/services/runner.rb +1 -1
- data/lib/taskwarrior-web/views/_flash.erb +7 -0
- data/lib/taskwarrior-web/views/_task_form.erb +28 -0
- data/lib/taskwarrior-web/views/delete_confirm.erb +4 -0
- data/lib/taskwarrior-web/views/edit_task.erb +13 -0
- data/lib/taskwarrior-web/views/layout.erb +1 -7
- data/lib/taskwarrior-web/views/listing.erb +4 -0
- data/lib/taskwarrior-web/views/new_task.erb +11 -0
- data/lib/taskwarrior-web/views/project.erb +2 -0
- data/lib/taskwarrior-web/views/projects.erb +2 -0
- data/spec/app/app_spec.rb +127 -20
- data/spec/model/task_spec.rb +20 -0
- data/spec/services/builder/base_spec.rb +6 -0
- data/spec/services/runner_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/taskwarrior-web.gemspec +3 -2
- metadata +48 -33
- data/lib/taskwarrior-web/views/task_form.erb +0 -38
data/.travis.yml
CHANGED
@@ -4,6 +4,7 @@ rvm:
|
|
4
4
|
- 1.9.3
|
5
5
|
script: "rake spec"
|
6
6
|
before_install:
|
7
|
-
- sudo apt-get
|
7
|
+
- sudo apt-get update -qq
|
8
|
+
- sudo apt-get install task -qq
|
8
9
|
- cp -v /home/vagrant/builds/theunraveler/taskwarrior-web/spec/files/taskrc /home/vagrant/.taskrc
|
9
10
|
- mkdir /home/vagrant/.task
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## v1.1.0 (12/7/12)
|
2
|
+
|
3
|
+
* Editing and deleting tasks! (If you are using task >= 2.0).
|
4
|
+
* Fixing status messages. They should now be consistent.
|
5
|
+
* Added safeguards for xterm.title and color .taskrc settings. You should now
|
6
|
+
be able to safely set both of those options.
|
7
|
+
|
1
8
|
## v1.0.14 (11/22/12)
|
2
9
|
|
3
10
|
* Fixed a bug when colorizing tasks based on "due" setting.
|
data/README.md
CHANGED
@@ -13,10 +13,6 @@ forthcoming!**
|
|
13
13
|
|
14
14
|
* `ruby` >= 1.9 (support for `ruby` < 1.9 is very unlikely, but pull requests
|
15
15
|
are gladly accepted).
|
16
|
-
* In your `.taskrc` file, `xterm.title` cannot be enabled. Either remove that
|
17
|
-
line from `.taskrc` or set it to `off`. If you have a very compelling reason
|
18
|
-
for needing this to be enabled, submit a bug report and I'll reconsider
|
19
|
-
adding support for it.
|
20
16
|
|
21
17
|
## Installation
|
22
18
|
|
@@ -37,8 +33,9 @@ an executable, so all options for Vegas are valid for `task-web`. Type
|
|
37
33
|
|
38
34
|
The current featureset includes:
|
39
35
|
|
40
|
-
* Viewing tasks
|
36
|
+
* Viewing tasks sorted and grouped in various ways.
|
41
37
|
* Creating a new task with a due date, project, and tags.
|
38
|
+
* Editing and deleting tasks (only task >= 2.0).
|
42
39
|
* `task-web` will pull your `task` config (from `.taskrc`) and use it to
|
43
40
|
determine date formatting and when an upcoming task should be marked as
|
44
41
|
"due".
|
data/lib/taskwarrior-web.rb
CHANGED
@@ -4,6 +4,7 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|
4
4
|
require 'rubygems'
|
5
5
|
require 'active_support/core_ext/object/blank'
|
6
6
|
require 'active_support/core_ext/string/inflections'
|
7
|
+
require 'active_support/core_ext/string/filters'
|
7
8
|
|
8
9
|
module TaskwarriorWeb
|
9
10
|
autoload :App, 'taskwarrior-web/app'
|
data/lib/taskwarrior-web/app.rb
CHANGED
@@ -6,6 +6,7 @@ require 'time'
|
|
6
6
|
require 'rinku'
|
7
7
|
require 'digest'
|
8
8
|
require 'sinatra/simple-navigation'
|
9
|
+
require 'rack-flash'
|
9
10
|
|
10
11
|
class TaskwarriorWeb::App < Sinatra::Base
|
11
12
|
autoload :Helpers, 'taskwarrior-web/helpers'
|
@@ -15,34 +16,25 @@ class TaskwarriorWeb::App < Sinatra::Base
|
|
15
16
|
set :app_file, __FILE__
|
16
17
|
set :public_folder, File.dirname(__FILE__) + '/public'
|
17
18
|
set :views, File.dirname(__FILE__) + '/views'
|
19
|
+
set :method_override, true
|
20
|
+
enable :sessions
|
18
21
|
|
19
22
|
# Helpers
|
20
23
|
helpers Helpers
|
21
24
|
register Sinatra::SimpleNavigation
|
25
|
+
use Rack::Flash
|
22
26
|
|
23
|
-
def protected!
|
24
|
-
response['WWW-Authenticate'] = %(Basic realm="Taskworrior Web") and throw(:halt, [401, "Not authorized\n"]) and return unless authorized?
|
25
|
-
end
|
26
|
-
|
27
|
-
def authorized?
|
28
|
-
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
29
|
-
values = [TaskwarriorWeb::Config.property('task-web.user'), TaskwarriorWeb::Config.property('task-web.passwd')]
|
30
|
-
@auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == values
|
31
|
-
end
|
32
|
-
|
33
27
|
# Before filter
|
34
28
|
before do
|
35
29
|
@current_page = request.path_info
|
30
|
+
@can_edit = TaskwarriorWeb::Config.supports? :editing
|
36
31
|
protected! if TaskwarriorWeb::Config.property('task-web.user')
|
37
32
|
end
|
38
33
|
|
39
34
|
# Redirects
|
40
|
-
get '/'
|
41
|
-
|
42
|
-
|
43
|
-
get '/tasks/?' do
|
44
|
-
redirect '/tasks/pending'
|
45
|
-
end
|
35
|
+
get('/') { redirect to('/tasks/pending') }
|
36
|
+
get('/tasks/?') { redirect to('/tasks/pending') }
|
37
|
+
get('/projects/?') { redirect to('/projects/overview') }
|
46
38
|
|
47
39
|
# Task routes
|
48
40
|
get '/tasks/:status/?' do
|
@@ -60,26 +52,63 @@ class TaskwarriorWeb::App < Sinatra::Base
|
|
60
52
|
get '/tasks/new/?' do
|
61
53
|
@title = 'New Task'
|
62
54
|
@date_format = (TaskwarriorWeb::Config.dateformat || 'm/d/yy').gsub('Y', 'yy')
|
63
|
-
erb :
|
55
|
+
erb :new_task
|
64
56
|
end
|
65
57
|
|
66
58
|
post '/tasks/?' do
|
67
59
|
@task = TaskwarriorWeb::Task.new(params[:task])
|
68
60
|
|
69
61
|
if @task.is_valid?
|
70
|
-
@task.save!
|
71
|
-
redirect '/tasks'
|
62
|
+
flash[:success] = @task.save! || %Q{New task "#{@task.description.truncate(20)}" created}
|
63
|
+
redirect to('/tasks')
|
72
64
|
end
|
73
65
|
|
74
|
-
|
75
|
-
|
66
|
+
flash.now[:error] = @task._errors.join(', ')
|
67
|
+
forward '/tasks/new'
|
76
68
|
end
|
77
69
|
|
78
|
-
|
79
|
-
|
80
|
-
|
70
|
+
get '/tasks/:uuid/?' do
|
71
|
+
not_found if !TaskwarriorWeb::Config.supports?(:editing)
|
72
|
+
tasks = TaskwarriorWeb::Task.find_by_uuid(params[:uuid])
|
73
|
+
not_found if tasks.empty?
|
74
|
+
@task = tasks.first
|
75
|
+
@title = %Q{Editing "#{@task.description.truncate(20)}"}
|
76
|
+
erb :edit_task
|
81
77
|
end
|
82
78
|
|
79
|
+
patch '/tasks/:uuid/?' do
|
80
|
+
not_found if !TaskwarriorWeb::Config.supports?(:editing)
|
81
|
+
not_found if TaskwarriorWeb::Task.find_by_uuid(params[:uuid]).empty?
|
82
|
+
|
83
|
+
@task = TaskwarriorWeb::Task.new(params[:task])
|
84
|
+
if @task.is_valid?
|
85
|
+
flash[:success] = @task.save! || %Q{Task "#{@task.description.truncate(20)}" was successfully updated}
|
86
|
+
redirect to('/tasks')
|
87
|
+
end
|
88
|
+
|
89
|
+
flash.now[:error] = @task._errors.join(', ')
|
90
|
+
forward "/tasks/#{@task.uuid}"
|
91
|
+
end
|
92
|
+
|
93
|
+
get '/tasks/:uuid/delete/?' do
|
94
|
+
not_found if !TaskwarriorWeb::Config.supports?(:editing)
|
95
|
+
tasks = TaskwarriorWeb::Task.find_by_uuid(params[:uuid])
|
96
|
+
not_found if tasks.empty?
|
97
|
+
@task = tasks.first
|
98
|
+
@title = %Q{Are you sure you want to delete the task "#{@task.description.truncate(20)}"?}
|
99
|
+
erb :delete_confirm
|
100
|
+
end
|
101
|
+
|
102
|
+
delete '/tasks/:uuid' do
|
103
|
+
not_found if !TaskwarriorWeb::Config.supports?(:editing)
|
104
|
+
tasks = TaskwarriorWeb::Task.find_by_uuid(params[:uuid])
|
105
|
+
not_found if tasks.empty?
|
106
|
+
@task = tasks.first
|
107
|
+
flash[:success] = @task.delete! || %Q{The task "#{@task.description.truncate(20)}" was successfully deleted}
|
108
|
+
redirect to('/tasks')
|
109
|
+
end
|
110
|
+
|
111
|
+
# Projects
|
83
112
|
get '/projects/overview/?' do
|
84
113
|
@title = 'Projects'
|
85
114
|
@tasks = TaskwarriorWeb::Task.query('status.not' => :deleted, 'project.not' => '')
|
@@ -90,49 +119,30 @@ class TaskwarriorWeb::App < Sinatra::Base
|
|
90
119
|
end
|
91
120
|
|
92
121
|
get '/projects/:name/?' do
|
93
|
-
@title = params[:name]
|
122
|
+
@title = unlinkify(params[:name])
|
94
123
|
@tasks = TaskwarriorWeb::Task.query('status.not' => 'deleted', :project => @title)
|
95
124
|
.sort_by! { |x| [x.priority.nil?.to_s, x.priority.to_s, x.due.nil?.to_s, x.due.to_s] }
|
96
125
|
erb :project
|
97
126
|
end
|
98
127
|
|
99
128
|
# AJAX callbacks
|
100
|
-
get
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
get '/ajax/count/?' do
|
105
|
-
self.class.task_count
|
106
|
-
end
|
129
|
+
get('/ajax/projects/?') { TaskwarriorWeb::Command.new(:projects).run.split("\n").to_json }
|
130
|
+
get('/ajax/count/?') { task_count }
|
131
|
+
post('/ajax/task-complete/:id/?') { TaskwarriorWeb::Command.new(:complete, params[:id]).run }
|
107
132
|
|
108
|
-
get '/ajax/badge
|
133
|
+
get '/ajax/badge/?' do
|
109
134
|
if filter = TaskwarriorWeb::Config.property('task-web.filter.badge')
|
110
135
|
total = TaskwarriorWeb::Task.query(:description => filter).count
|
111
136
|
else
|
112
|
-
total =
|
137
|
+
total = task_count
|
113
138
|
end
|
114
139
|
total == 0 ? '' : total.to_s
|
115
140
|
end
|
116
141
|
|
117
|
-
post '/ajax/task-complete/:id/?' do
|
118
|
-
# Bummer that we have to directly use Command here, but apparently tasks
|
119
|
-
# cannot be filtered by UUID.
|
120
|
-
TaskwarriorWeb::Command.new(:complete, params[:id]).run
|
121
|
-
end
|
122
|
-
|
123
142
|
# Error handling
|
124
143
|
not_found do
|
125
144
|
@title = 'Page Not Found'
|
126
145
|
@referrer = request.referrer
|
127
146
|
erb :'404'
|
128
147
|
end
|
129
|
-
|
130
|
-
def self.task_count
|
131
|
-
if filter = TaskwarriorWeb::Config.property('task-web.filter')
|
132
|
-
total = TaskwarriorWeb::Task.query(:description => filter).count
|
133
|
-
else
|
134
|
-
total = TaskwarriorWeb::Task.count(:status => :pending)
|
135
|
-
end
|
136
|
-
total.to_s
|
137
|
-
end
|
138
148
|
end
|
@@ -5,7 +5,7 @@ SimpleNavigation::Configuration.run do |navigation|
|
|
5
5
|
primary.dom_class = 'nav'
|
6
6
|
primary.item :tasks, 'Tasks', '/tasks' do |tasks|
|
7
7
|
tasks.dom_class = 'nav nav-pills'
|
8
|
-
tasks.item :pending, "Pending <span class=\"badge\">#{
|
8
|
+
tasks.item :pending, "Pending <span class=\"badge\">#{task_count}</span>", '/tasks/pending'
|
9
9
|
tasks.item :waiting, 'Waiting', '/tasks/waiting'
|
10
10
|
tasks.item :completed, 'Completed', '/tasks/completed'
|
11
11
|
tasks.item :deleted, 'Deleted', '/tasks/deleted'
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/date/calculations'
|
2
2
|
|
3
3
|
module TaskwarriorWeb::App::Helpers
|
4
|
-
|
5
4
|
def format_date(timestamp)
|
6
5
|
format = TaskwarriorWeb::Config.dateformat || '%-m/%-d/%Y'
|
7
6
|
Time.parse(timestamp).strftime(format)
|
@@ -20,11 +19,49 @@ module TaskwarriorWeb::App::Helpers
|
|
20
19
|
end
|
21
20
|
|
22
21
|
def linkify(item)
|
23
|
-
|
24
|
-
|
22
|
+
item.gsub('.', '--') unless item.nil? unless item.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def unlinkify(item)
|
26
|
+
item.gsub('--', '.') unless item.nil?
|
25
27
|
end
|
26
28
|
|
27
29
|
def auto_link(text)
|
28
30
|
Rinku.auto_link(text, :all, 'target="_blank"')
|
29
31
|
end
|
32
|
+
|
33
|
+
def flash_types
|
34
|
+
[:success, :info, :warning, :error]
|
35
|
+
end
|
36
|
+
|
37
|
+
def task_count
|
38
|
+
if filter = TaskwarriorWeb::Config.property('task-web.filter')
|
39
|
+
total = TaskwarriorWeb::Task.query(:description => filter).count
|
40
|
+
else
|
41
|
+
total = TaskwarriorWeb::Task.count(:status => :pending)
|
42
|
+
end
|
43
|
+
total.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def crud_links(task)
|
47
|
+
string = %Q{<a href="/tasks/#{task.uuid}">Edit</a>}
|
48
|
+
string << %Q{ | }
|
49
|
+
string << %Q{<a href="/tasks/#{task.uuid}/delete">Delete</a>}
|
50
|
+
string
|
51
|
+
end
|
52
|
+
|
53
|
+
# Authentication
|
54
|
+
def protected!
|
55
|
+
response['WWW-Authenticate'] = %(Basic realm="Taskworrior Web") and throw(:halt, [401, "Not authorized\n"]) and return unless authorized?
|
56
|
+
end
|
57
|
+
|
58
|
+
def authorized?
|
59
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
60
|
+
values = [TaskwarriorWeb::Config.property('task-web.user'), TaskwarriorWeb::Config.property('task-web.passwd')]
|
61
|
+
@auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == values
|
62
|
+
end
|
63
|
+
|
64
|
+
def forward(url, method = 'GET')
|
65
|
+
call env.merge('REQUEST_METHOD' => method, 'PATH_INFO' => url)
|
66
|
+
end
|
30
67
|
end
|
@@ -22,7 +22,7 @@ module TaskwarriorWeb::Config
|
|
22
22
|
}
|
23
23
|
|
24
24
|
def self.version
|
25
|
-
@version ||= Versionomy.parse(
|
25
|
+
@version ||= Versionomy.parse(`#{TaskwarriorWeb::Runner::TASK_BIN} _version`.strip)
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.file
|
@@ -37,6 +37,13 @@ module TaskwarriorWeb::Config
|
|
37
37
|
self.file['dateformat'].gsub(/(\w)/, DATEFORMATS) unless self.file['dateformat'].nil?
|
38
38
|
end
|
39
39
|
|
40
|
+
def self.supports?(feature)
|
41
|
+
case feature.to_sym
|
42
|
+
when :editing then self.version.major > 1
|
43
|
+
else false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
40
47
|
def self.method_missing(method)
|
41
48
|
self.file[method.to_s]
|
42
49
|
end
|
@@ -7,7 +7,7 @@ module TaskwarriorWeb
|
|
7
7
|
|
8
8
|
attr_accessor :entry, :project, :priority, :uuid, :description, :status,
|
9
9
|
:due, :start, :end, :tags, :depends, :wait, :annotations,
|
10
|
-
:_errors
|
10
|
+
:_errors, :remove_tags
|
11
11
|
alias :annotate= :annotations=
|
12
12
|
|
13
13
|
####################################
|
@@ -24,16 +24,24 @@ module TaskwarriorWeb
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def save!
|
27
|
-
Command.new(:add, nil, self.to_hash).run
|
27
|
+
@uuid ? Command.new(:update, uuid, self.to_hash).run : Command.new(:add, nil, self.to_hash).run
|
28
28
|
end
|
29
29
|
|
30
30
|
def complete!
|
31
31
|
Command.new(:complete, self.uuid).run
|
32
32
|
end
|
33
33
|
|
34
|
+
def delete!
|
35
|
+
Command.new(:delete, self.uuid).run
|
36
|
+
end
|
37
|
+
|
34
38
|
# Make sure that the tags are an array.
|
35
39
|
def tags=(value)
|
36
40
|
@tags = value.is_a?(String) ? value.split(/[, ]+/).reject(&:empty?) : value
|
41
|
+
|
42
|
+
if @uuid
|
43
|
+
@remove_tags = Task.find_by_uuid(uuid).first.tags - @tags
|
44
|
+
end
|
37
45
|
end
|
38
46
|
|
39
47
|
def is_valid?
|
@@ -71,7 +71,7 @@ var initTaskCompletion = function() {
|
|
71
71
|
|
72
72
|
var refreshDockBadge = function() {
|
73
73
|
if (window.hasOwnProperty('fluid')) {
|
74
|
-
$.get('/ajax/badge
|
74
|
+
$.get('/ajax/badge', function(data) {
|
75
75
|
window.fluid.dockBadge = data;
|
76
76
|
});
|
77
77
|
}
|
@@ -90,5 +90,7 @@ var refreshSubnavCount = function() {
|
|
90
90
|
* @param string [severity] The severity of the message.
|
91
91
|
*/
|
92
92
|
function set_message(msg, severity) {
|
93
|
-
$('
|
93
|
+
$('<div style="display: none;" class="alert alert-' + (severity || 'success') + '">' + msg + '</div>')
|
94
|
+
.appendTo('#flash-messages')
|
95
|
+
.fadeIn();
|
94
96
|
}
|
@@ -4,6 +4,8 @@ module TaskwarriorWeb::CommandBuilder::Base
|
|
4
4
|
|
5
5
|
TASK_COMMANDS = {
|
6
6
|
:add => 'add',
|
7
|
+
:update => TaskwarriorWeb::Config.version.major >= 2 ? ':id mod' : nil,
|
8
|
+
:delete => 'rc.confirmation=no :id delete',
|
7
9
|
:query => TaskwarriorWeb::Config.version > Versionomy.parse('1.9.2') ? '_query' : 'export',
|
8
10
|
:complete => ':id done',
|
9
11
|
:projects => '_projects',
|
@@ -20,7 +22,7 @@ module TaskwarriorWeb::CommandBuilder::Base
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def task_command
|
23
|
-
if TASK_COMMANDS
|
25
|
+
if TASK_COMMANDS[@command.to_sym]
|
24
26
|
@command_string = TASK_COMMANDS[@command.to_sym].clone
|
25
27
|
return self
|
26
28
|
else
|
@@ -45,6 +47,10 @@ module TaskwarriorWeb::CommandBuilder::Base
|
|
45
47
|
tags.each { |tag| string << %Q( #{tag_indicator}#{tag.to_s.shellescape}) }
|
46
48
|
end
|
47
49
|
|
50
|
+
if tags = @params.delete(:remove_tags)
|
51
|
+
tags.each { |tag| string << %Q( -#{tag.to_s.shellescape}) }
|
52
|
+
end
|
53
|
+
|
48
54
|
@params.each do |attr, value|
|
49
55
|
if value.respond_to? :each
|
50
56
|
value.each { |val| string << %Q( #{attr.to_s}:\\"#{val.to_s.shellescape}\\") }
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<div class="control-group">
|
2
|
+
<label for="task-description" class="control-label">Description</label>
|
3
|
+
<div class="controls">
|
4
|
+
<input type="textfield" id="task-description" name="task[description]" value="<%= @task.description unless @task.nil? %>" />
|
5
|
+
</div>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<div class="control-group">
|
9
|
+
<label for="task-project" class="control-label">Project</label>
|
10
|
+
<div class="controls">
|
11
|
+
<input type="textfield" id="task-project" name="task[project]" value="<%= @task.project unless @task.nil? %>" autocomplete="off" />
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<div class="control-group">
|
16
|
+
<label for="task-due" class="control-label">Due Date</label>
|
17
|
+
<div class="controls">
|
18
|
+
<input class="date-picker" type="textfield" id="task-due" name="task[due]" value="<%= format_date(@task.due) unless @task.nil? || @task.due.blank? %>" data-date-format="<%= @date_format %>" />
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<div class="control-group">
|
23
|
+
<label for="task-tags" class="control-label">Tags</label>
|
24
|
+
<div class="controls">
|
25
|
+
<input type="textfield" id="task-tags" name="task[tags]" value="<%= @task.tags.join(', ') unless @task.nil? %>" autocomplete="off" />
|
26
|
+
<span class="help-block">Enter tags separated by commas or spaces (e.g. <em>each, word will,be a tag</em>)</span>
|
27
|
+
</div>
|
28
|
+
</div>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<form id="new-task-form" class="form-horizontal" action="/tasks/<%= @task.uuid %>" method="post">
|
2
|
+
<input type="hidden" name="task[uuid]" value="<%= @task.uuid %>" />
|
3
|
+
|
4
|
+
<%= erb :_task_form %>
|
5
|
+
|
6
|
+
<div class="control-group">
|
7
|
+
<div class="controls">
|
8
|
+
<button type="submit" class="btn btn-primary">Update Task</button>
|
9
|
+
<input type="hidden" name="_method" value="patch" />
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
</form>
|
@@ -19,13 +19,7 @@
|
|
19
19
|
<%= erb :_topbar %>
|
20
20
|
<%= erb :_subnav %>
|
21
21
|
<section class="content">
|
22
|
-
|
23
|
-
<% if @messages %>
|
24
|
-
<% @messages.each do |message| %>
|
25
|
-
<div class="alert <%= message[:severity] %>"><%= message[:message] %></div>
|
26
|
-
<% end %>
|
27
|
-
<% end %>
|
28
|
-
</div>
|
22
|
+
<%= erb :_flash %>
|
29
23
|
<%= yield %>
|
30
24
|
</section>
|
31
25
|
</div>
|
@@ -1,3 +1,5 @@
|
|
1
|
+
<% can_edit = @can_edit && params[:status] == 'pending' %>
|
2
|
+
|
1
3
|
<div id="listing">
|
2
4
|
<table class="table table-striped table-hover">
|
3
5
|
<thead>
|
@@ -10,6 +12,7 @@
|
|
10
12
|
<th>Due</th>
|
11
13
|
<th>Tags</th>
|
12
14
|
<th>Priority</th>
|
15
|
+
<% if @can_edit %><th></th><% end %>
|
13
16
|
</tr>
|
14
17
|
</thead>
|
15
18
|
<tbody>
|
@@ -36,6 +39,7 @@
|
|
36
39
|
<td><%= format_date(task.due) unless task.due.nil? %></td>
|
37
40
|
<td><%= task.tags.join(', ') unless task.tags.nil? %></td>
|
38
41
|
<td><%= task.priority unless task.priority.nil? %></td>
|
42
|
+
<% if can_edit %><td><%= crud_links(task) %></td><% end %>
|
39
43
|
</tr>
|
40
44
|
<% end %>
|
41
45
|
</tbody>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<form id="new-task-form" class="form-horizontal" action="/tasks" method="post">
|
2
|
+
|
3
|
+
<%= erb :_task_form %>
|
4
|
+
|
5
|
+
<div class="control-group">
|
6
|
+
<div class="controls">
|
7
|
+
<button type="submit" class="btn btn-primary">Create Task</button>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
</form>
|
@@ -6,6 +6,7 @@
|
|
6
6
|
<th>Due</th>
|
7
7
|
<th>Tags</th>
|
8
8
|
<th>Priority</th>
|
9
|
+
<% if @can_edit %><th></th><% end %>
|
9
10
|
</tr>
|
10
11
|
</thead>
|
11
12
|
<tbody>
|
@@ -16,6 +17,7 @@
|
|
16
17
|
<td><%= format_date(task.due) unless task.due.nil? %></td>
|
17
18
|
<td><%= task.tags.join(', ') unless task.tags.nil? %></td>
|
18
19
|
<td><%= task.priority unless task.priority.nil? %></td>
|
20
|
+
<% if @can_edit %><td><%= crud_links(task) %></td><% end %>
|
19
21
|
</tr>
|
20
22
|
<% end %>
|
21
23
|
<% end %>
|
@@ -28,6 +28,7 @@
|
|
28
28
|
<th>Due</th>
|
29
29
|
<th>Tags</th>
|
30
30
|
<th>Priority</th>
|
31
|
+
<% if @can_edit %><th></th><% end %>
|
31
32
|
</tr>
|
32
33
|
</thead>
|
33
34
|
<tbody>
|
@@ -38,6 +39,7 @@
|
|
38
39
|
<td><%= format_date(task.due) unless task.due.nil? %></td>
|
39
40
|
<td><%= task.tags.join(', ') unless task.tags.nil? %></td>
|
40
41
|
<td><%= task.priority unless task.priority.nil? %></td>
|
42
|
+
<% if @can_edit %><td><%= crud_links(task) %></td><% end %>
|
41
43
|
</tr>
|
42
44
|
<% end %>
|
43
45
|
<% end %>
|
data/spec/app/app_spec.rb
CHANGED
@@ -22,26 +22,16 @@ describe TaskwarriorWeb::App do
|
|
22
22
|
get path
|
23
23
|
follow_redirect!
|
24
24
|
|
25
|
-
last_request.url.should
|
25
|
+
last_request.url.should match(/tasks\/pending$/)
|
26
26
|
last_response.should be_ok
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
describe 'GET /projects' do
|
32
|
-
it 'should redirect to /projects/overview' do
|
33
|
-
get '/projects'
|
34
|
-
follow_redirect!
|
35
|
-
|
36
|
-
last_request.url.should =~ /projects\/overview/
|
37
|
-
last_response.should be_ok
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
31
|
describe 'GET /tasks/new' do
|
42
32
|
it 'should display a new task form' do
|
43
33
|
get '/tasks/new'
|
44
|
-
last_response.body.should
|
34
|
+
last_response.body.should include('<form')
|
45
35
|
end
|
46
36
|
|
47
37
|
it 'should display a 200 status code' do
|
@@ -60,13 +50,13 @@ describe TaskwarriorWeb::App do
|
|
60
50
|
end
|
61
51
|
|
62
52
|
it 'should redirect to the task listing page' do
|
63
|
-
task = TaskwarriorWeb::Task.new
|
53
|
+
task = TaskwarriorWeb::Task.new({:description => 'Test task'})
|
64
54
|
task.should_receive(:is_valid?).and_return(true)
|
65
55
|
task.should_receive(:save!)
|
66
56
|
TaskwarriorWeb::Task.should_receive(:new).once.and_return(task)
|
67
|
-
post '/tasks', :task => {}
|
57
|
+
post '/tasks', :task => {:description => 'Test task'}
|
68
58
|
follow_redirect!
|
69
|
-
last_request.url.should
|
59
|
+
last_request.url.should match(/tasks$/)
|
70
60
|
end
|
71
61
|
end
|
72
62
|
|
@@ -82,17 +72,134 @@ describe TaskwarriorWeb::App do
|
|
82
72
|
task = TaskwarriorWeb::Task.new({:tags => 'tag1, tag2'})
|
83
73
|
TaskwarriorWeb::Task.should_receive(:new).once.and_return(task)
|
84
74
|
post '/tasks', :task => {}
|
85
|
-
last_response.body.should
|
86
|
-
last_response.body.should
|
75
|
+
last_response.body.should include('form')
|
76
|
+
last_response.body.should include('tag1, tag2')
|
87
77
|
end
|
88
78
|
|
89
79
|
it 'should display errors messages' do
|
90
80
|
task = TaskwarriorWeb::Task.new
|
91
81
|
TaskwarriorWeb::Task.should_receive(:new).once.and_return(task)
|
92
82
|
post '/tasks', :task => {}
|
93
|
-
last_response.body.should
|
83
|
+
last_response.body.should include('You must provide a description')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe 'GET /tasks/:uuid' do
|
89
|
+
context 'given a non-existant task' do
|
90
|
+
it 'should return a 404' do
|
91
|
+
TaskwarriorWeb::Task.should_receive(:find_by_uuid).and_return([])
|
92
|
+
get '/tasks/1'
|
93
|
+
last_response.should be_not_found
|
94
94
|
end
|
95
95
|
end
|
96
|
+
|
97
|
+
context 'given an existing task' do
|
98
|
+
before do
|
99
|
+
TaskwarriorWeb::Task.should_receive(:find_by_uuid).and_return([
|
100
|
+
TaskwarriorWeb::Task.new({:uuid => 246, :description => 'Test task with a longer description'})
|
101
|
+
])
|
102
|
+
get '/tasks/246'
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should render an edit form' do
|
106
|
+
last_response.body.should have_tag('form', :with => { :action => '/tasks/246', :method => 'post' }) do
|
107
|
+
with_tag('input', :with => { :name => '_method', :value => 'patch' })
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should set the HTTP method in the form' do
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should truncate the task description' do
|
115
|
+
last_response.body.should have_tag('title', :text => /Test task with a .../)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should fill the form fields with existing data' do
|
119
|
+
last_response.body.should have_tag('input', :with => { :name => 'task[description]', :value => 'Test task with a longer description' })
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe 'PATCH /tasks/:uuid' do
|
125
|
+
context 'given a non-existant task' do
|
126
|
+
it 'should return a 404' do
|
127
|
+
TaskwarriorWeb::Task.should_receive(:find_by_uuid).and_return([])
|
128
|
+
patch '/tasks/429897527'
|
129
|
+
last_response.should be_not_found
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe 'GET /tasks/:uuid/delete' do
|
135
|
+
context 'given a non-existant task' do
|
136
|
+
it 'should return a 404' do
|
137
|
+
TaskwarriorWeb::Task.should_receive(:find_by_uuid).and_return([])
|
138
|
+
get '/tasks/429897527/delete'
|
139
|
+
last_response.should be_not_found
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'given an existing task' do
|
144
|
+
before do
|
145
|
+
TaskwarriorWeb::Task.should_receive(:find_by_uuid).and_return([
|
146
|
+
TaskwarriorWeb::Task.new({:uuid => 246, :description => 'Test task with a longer description'})
|
147
|
+
])
|
148
|
+
get '/tasks/246/delete'
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should show a delete form' do
|
152
|
+
last_response.body.should have_tag('form', :with => { :action => '/tasks/246', :method => 'post' }) do
|
153
|
+
with_tag('input', :with => { :name => '_method', :value => 'delete' })
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'should display a delete button' do
|
158
|
+
last_response.body.should have_tag('input', :with => { :type => 'submit', :value => 'Delete' })
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe 'DELETE /tasks/:uuid' do
|
164
|
+
context 'given a non-existant task' do
|
165
|
+
it 'should return a 404' do
|
166
|
+
TaskwarriorWeb::Task.should_receive(:find_by_uuid).and_return([])
|
167
|
+
delete '/tasks/429897527'
|
168
|
+
last_response.should be_not_found
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context 'given an existing task' do
|
173
|
+
before do
|
174
|
+
@task = TaskwarriorWeb::Task.new
|
175
|
+
@task.should_receive(:delete!).once.and_return('Success')
|
176
|
+
TaskwarriorWeb::Task.should_receive(:find_by_uuid).and_return([@task])
|
177
|
+
delete '/tasks/246'
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should redirect to the task overview page' do
|
181
|
+
follow_redirect!
|
182
|
+
last_request.url.should match(/tasks$/)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe 'GET /projects' do
|
188
|
+
it 'should redirect to /projects/overview' do
|
189
|
+
get '/projects'
|
190
|
+
follow_redirect!
|
191
|
+
|
192
|
+
last_request.url.should match(/projects\/overview$/)
|
193
|
+
last_response.should be_ok
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
describe 'GET /projects/:name' do
|
198
|
+
it 'should replace characters in the title' do
|
199
|
+
TaskwarriorWeb::Task.should_receive(:query).any_number_of_times.and_return([])
|
200
|
+
get '/projects/Test--Project'
|
201
|
+
last_response.body.should include('<title>Test.Project')
|
202
|
+
end
|
96
203
|
end
|
97
204
|
|
98
205
|
describe 'GET /ajax/projects' do
|
@@ -126,12 +233,12 @@ describe TaskwarriorWeb::App do
|
|
126
233
|
describe 'not_found' do
|
127
234
|
it 'should set the title to "Not Found"' do
|
128
235
|
get '/page-not-found'
|
129
|
-
last_response.body.should
|
236
|
+
last_response.body.should include('<title>Page Not Found')
|
130
237
|
end
|
131
238
|
|
132
239
|
it 'should have a status code of 404' do
|
133
240
|
get '/page-not-found'
|
134
|
-
last_response.
|
241
|
+
last_response.should be_not_found
|
135
242
|
end
|
136
243
|
end
|
137
244
|
end
|
data/spec/model/task_spec.rb
CHANGED
@@ -38,6 +38,16 @@ describe TaskwarriorWeb::Task do
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
describe '#delete!' do
|
42
|
+
it 'should delete the task' do
|
43
|
+
task = TaskwarriorWeb::Task.new({:uuid => 15})
|
44
|
+
command = TaskwarriorWeb::Command.new(:delete)
|
45
|
+
command.should_receive(:run).once
|
46
|
+
TaskwarriorWeb::Command.should_receive(:new).once.with(:delete, 15).and_return(command)
|
47
|
+
task.delete!
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
41
51
|
describe '.query' do
|
42
52
|
before do
|
43
53
|
@command = TaskwarriorWeb::Command.new(:query)
|
@@ -82,6 +92,16 @@ describe TaskwarriorWeb::Task do
|
|
82
92
|
task = TaskwarriorWeb::Task.new(:tags => '@hi, -twice, !again, ~when')
|
83
93
|
task.tags.should eq(['@hi', '-twice', '!again', '~when'])
|
84
94
|
end
|
95
|
+
|
96
|
+
it 'should properly set tags for removal' do
|
97
|
+
task = TaskwarriorWeb::Task.new({:tags => ['hello', 'goodbye']})
|
98
|
+
TaskwarriorWeb::Task.should_receive(:find_by_uuid).and_return([task])
|
99
|
+
task2 = TaskwarriorWeb::Task.new
|
100
|
+
task2.uuid = 15
|
101
|
+
task2.tags = ['goodbye']
|
102
|
+
task2.tags.should eq(['goodbye'])
|
103
|
+
task2.remove_tags.should eq(['hello'])
|
104
|
+
end
|
85
105
|
end
|
86
106
|
|
87
107
|
describe '#to_hash' do
|
@@ -51,6 +51,12 @@ describe TaskwarriorWeb::CommandBuilder::Base do
|
|
51
51
|
command.params.should eq(' +today +tomorrow')
|
52
52
|
end
|
53
53
|
|
54
|
+
it 'should remove tags using a -' do
|
55
|
+
command = TaskwarriorWeb::Command.new(:add, nil, :remove_tags => [:test, :tag])
|
56
|
+
command.parse_params
|
57
|
+
command.params.should eq(' -test -tag')
|
58
|
+
end
|
59
|
+
|
54
60
|
it 'should pull out the description parameter' do
|
55
61
|
command = TaskwarriorWeb::Command.new(:add, nil, :description => 'Hello', :status => :pending)
|
56
62
|
command.parse_params
|
data/spec/spec_helper.rb
CHANGED
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 = '1.0
|
6
|
+
s.version = '1.1.0'
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
8
|
s.authors = ["Jake Bell"]
|
9
9
|
s.email = ["jake@theunraveler.com"]
|
@@ -16,17 +16,18 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.required_ruby_version = '>= 1.9.0'
|
17
17
|
|
18
18
|
s.add_dependency('sinatra')
|
19
|
-
s.add_dependency('thin')
|
20
19
|
s.add_dependency('parseconfig')
|
21
20
|
s.add_dependency('vegas')
|
22
21
|
s.add_dependency('rinku')
|
23
22
|
s.add_dependency('versionomy')
|
24
23
|
s.add_dependency('activesupport')
|
25
24
|
s.add_dependency('sinatra-simple-navigation')
|
25
|
+
s.add_dependency('rack-flash3')
|
26
26
|
|
27
27
|
s.add_development_dependency('rake')
|
28
28
|
s.add_development_dependency('rack-test')
|
29
29
|
s.add_development_dependency('rspec')
|
30
|
+
s.add_development_dependency('rspec-html-matchers')
|
30
31
|
|
31
32
|
s.files = `git ls-files`.split("\n")
|
32
33
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
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: 1.0
|
4
|
+
version: 1.1.0
|
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-
|
12
|
+
date: 2012-12-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sinatra
|
16
|
-
requirement: &
|
16
|
+
requirement: &70274029036160 !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: *70274029036160
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
27
|
-
requirement: &
|
26
|
+
name: parseconfig
|
27
|
+
requirement: &70274029035440 !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: *70274029035440
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
38
|
-
requirement: &
|
37
|
+
name: vegas
|
38
|
+
requirement: &70274029034480 !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: *70274029034480
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
49
|
-
requirement: &
|
48
|
+
name: rinku
|
49
|
+
requirement: &70274029033940 !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: *70274029033940
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
|
-
name:
|
60
|
-
requirement: &
|
59
|
+
name: versionomy
|
60
|
+
requirement: &70274029032960 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70274029032960
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
71
|
-
requirement: &
|
70
|
+
name: activesupport
|
71
|
+
requirement: &70274029031920 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70274029031920
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
|
-
name:
|
82
|
-
requirement: &
|
81
|
+
name: sinatra-simple-navigation
|
82
|
+
requirement: &70274029031060 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70274029031060
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
|
-
name:
|
93
|
-
requirement: &
|
92
|
+
name: rack-flash3
|
93
|
+
requirement: &70274029030180 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :runtime
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70274029030180
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: rake
|
104
|
-
requirement: &
|
104
|
+
requirement: &70274029029420 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70274029029420
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: rack-test
|
115
|
-
requirement: &
|
115
|
+
requirement: &70274029028620 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,21 @@ dependencies:
|
|
120
120
|
version: '0'
|
121
121
|
type: :development
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *70274029028620
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: rspec
|
126
|
-
requirement: &
|
126
|
+
requirement: &70274029027800 !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: *70274029027800
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
name: rspec-html-matchers
|
137
|
+
requirement: &70274029027120 !ruby/object:Gem::Requirement
|
127
138
|
none: false
|
128
139
|
requirements:
|
129
140
|
- - ! '>='
|
@@ -131,7 +142,7 @@ dependencies:
|
|
131
142
|
version: '0'
|
132
143
|
type: :development
|
133
144
|
prerelease: false
|
134
|
-
version_requirements: *
|
145
|
+
version_requirements: *70274029027120
|
135
146
|
description: This gem provides a graphical frontend for the Taskwarrior task manager.
|
136
147
|
It is based on Sinatra.
|
137
148
|
email:
|
@@ -179,13 +190,17 @@ files:
|
|
179
190
|
- lib/taskwarrior-web/services/parser/json.rb
|
180
191
|
- lib/taskwarrior-web/services/runner.rb
|
181
192
|
- lib/taskwarrior-web/views/404.erb
|
193
|
+
- lib/taskwarrior-web/views/_flash.erb
|
182
194
|
- lib/taskwarrior-web/views/_subnav.erb
|
195
|
+
- lib/taskwarrior-web/views/_task_form.erb
|
183
196
|
- lib/taskwarrior-web/views/_topbar.erb
|
197
|
+
- lib/taskwarrior-web/views/delete_confirm.erb
|
198
|
+
- lib/taskwarrior-web/views/edit_task.erb
|
184
199
|
- lib/taskwarrior-web/views/layout.erb
|
185
200
|
- lib/taskwarrior-web/views/listing.erb
|
201
|
+
- lib/taskwarrior-web/views/new_task.erb
|
186
202
|
- lib/taskwarrior-web/views/project.erb
|
187
203
|
- lib/taskwarrior-web/views/projects.erb
|
188
|
-
- lib/taskwarrior-web/views/task_form.erb
|
189
204
|
- spec/app/app_spec.rb
|
190
205
|
- spec/app/helpers_spec.rb
|
191
206
|
- spec/files/taskrc
|
@@ -219,7 +234,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
219
234
|
version: '0'
|
220
235
|
segments:
|
221
236
|
- 0
|
222
|
-
hash:
|
237
|
+
hash: 649655695520079499
|
223
238
|
requirements: []
|
224
239
|
rubyforge_project: taskwarrior-web
|
225
240
|
rubygems_version: 1.8.11
|
@@ -1,38 +0,0 @@
|
|
1
|
-
<form id="new-task-form" class="form-horizontal" action="/tasks" method="post">
|
2
|
-
|
3
|
-
<div class="control-group">
|
4
|
-
<label for="task-description" class="control-label">Description</label>
|
5
|
-
<div class="controls">
|
6
|
-
<input type="textfield" id="task-description" name="task[description]" value="<%= @task.description unless @task.nil? %>" />
|
7
|
-
</div>
|
8
|
-
</div>
|
9
|
-
|
10
|
-
<div class="control-group">
|
11
|
-
<label for="task-project" class="control-label">Project</label>
|
12
|
-
<div class="controls">
|
13
|
-
<input type="textfield" id="task-project" name="task[project]" value="<%= @task.project unless @task.nil? %>" autocomplete="off" />
|
14
|
-
</div>
|
15
|
-
</div>
|
16
|
-
|
17
|
-
<div class="control-group">
|
18
|
-
<label for="task-due" class="control-label">Due Date</label>
|
19
|
-
<div class="controls">
|
20
|
-
<input class="date-picker" type="textfield" id="task-due" name="task[due]" value="<%= @task.due unless @task.nil? %>" data-date-format="<%= @date_format %>" />
|
21
|
-
</div>
|
22
|
-
</div>
|
23
|
-
|
24
|
-
<div class="control-group">
|
25
|
-
<label for="task-tags" class="control-label">Tags</label>
|
26
|
-
<div class="controls">
|
27
|
-
<input type="textfield" id="task-tags" name="task[tags]" value="<%= @task.tags.join(', ') unless @task.nil? %>" autocomplete="off" />
|
28
|
-
<span class="help-block">Enter tags separated by commas or spaces (e.g. <em>each, word will,be a tag</em>)</span>
|
29
|
-
</div>
|
30
|
-
</div>
|
31
|
-
|
32
|
-
<div class="control-group">
|
33
|
-
<div class="controls">
|
34
|
-
<button type="submit" class="btn">Create Task</button>
|
35
|
-
</div>
|
36
|
-
</div>
|
37
|
-
|
38
|
-
</form>
|