taskwarrior-web 1.1.7 → 1.1.8
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +6 -0
- data/README.md +12 -10
- data/lib/taskwarrior-web.rb +1 -0
- data/lib/taskwarrior-web/app.rb +47 -19
- data/lib/taskwarrior-web/helpers.rb +3 -1
- data/lib/taskwarrior-web/model/annotation.rb +26 -0
- data/lib/taskwarrior-web/model/task.rb +11 -2
- data/lib/taskwarrior-web/public/css/styles.css +3 -1
- data/lib/taskwarrior-web/public/js/application.js +34 -5
- data/lib/taskwarrior-web/services/builder/base.rb +2 -0
- data/lib/taskwarrior-web/version.rb +1 -1
- data/lib/taskwarrior-web/views/layout.erb +5 -5
- data/lib/taskwarrior-web/views/{_flash.erb → partials/_flash.erb} +1 -0
- data/lib/taskwarrior-web/views/{_footer.erb → partials/_footer.erb} +0 -0
- data/lib/taskwarrior-web/views/{_hotkeys.erb → partials/_hotkeys.erb} +2 -2
- data/lib/taskwarrior-web/views/{_subnav.erb → partials/_subnav.erb} +0 -0
- data/lib/taskwarrior-web/views/{_topbar.erb → partials/_topbar.erb} +0 -0
- data/lib/taskwarrior-web/views/{projects.erb → projects/index.erb} +5 -0
- data/lib/taskwarrior-web/views/{project.erb → projects/show.erb} +0 -0
- data/lib/taskwarrior-web/views/tasks/_annotation_form.erb +18 -0
- data/lib/taskwarrior-web/views/{_task_form.erb → tasks/_form.erb} +1 -1
- data/lib/taskwarrior-web/views/{edit_task.erb → tasks/edit.erb} +1 -1
- data/lib/taskwarrior-web/views/{listing.erb → tasks/index.erb} +12 -3
- data/lib/taskwarrior-web/views/{new_task.erb → tasks/new.erb} +1 -1
- data/spec/app/app_spec.rb +0 -29
- metadata +101 -40
- data/lib/taskwarrior-web/views/delete_confirm.erb +0 -4
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -5,6 +5,9 @@ wonderful [Taskwarrior](http://taskwarrior.org/) todo application.
|
|
5
5
|
|
6
6
|
![TaskwarriorWeb screenshot](https://dl.dropbox.com/u/107599300/screenshot.png)
|
7
7
|
|
8
|
+
[![Gem Version](https://badge.fury.io/rb/taskwarrior-web.png)](http://badge.fury.io/rb/taskwarrior-web)
|
9
|
+
[![Build Status](https://secure.travis-ci.org/theunraveler/taskwarrior-web.png)](http://travis-ci.org/theunraveler/taskwarrior-web)
|
10
|
+
|
8
11
|
## Requirements
|
9
12
|
|
10
13
|
* `ruby` >= 1.9 (support for `ruby` < 1.9 is very unlikely, but pull requests
|
@@ -37,24 +40,23 @@ The current featureset includes:
|
|
37
40
|
"due".
|
38
41
|
* If you are on a Mac and use Fluid.app, you get a dock badge showing the
|
39
42
|
number of pending tasks.
|
40
|
-
* Optional
|
41
|
-
|
43
|
+
* [Optional HTTP Basic authentication][1].
|
44
|
+
|
45
|
+
[1]: https://github.com/theunraveler/taskwarrior-web/wiki/Additional-.taskrc-options
|
42
46
|
|
43
47
|
## Reporting Bugs
|
44
48
|
|
45
|
-
To report a bug, use the [Github issue tracker][
|
49
|
+
To report a bug, use the [Github issue tracker][2]. Since `taskwarrior-web`
|
46
50
|
works with several different versions of `task`, using many different
|
47
51
|
configurations, please include the output from `task _version` and either the
|
48
52
|
output of `task show` or a copy of your `.taskrc` file when filing a bug. This helps me reproduce bugs easier.
|
49
53
|
|
50
|
-
Here is an example of a [good bug report][
|
54
|
+
Here is an example of a [good bug report][3].
|
51
55
|
|
52
|
-
[
|
53
|
-
[
|
56
|
+
[2]: http://github.com/theunraveler/taskwarrior-web/issues
|
57
|
+
[3]: http://github.com/theunraveler/taskwarrior-web/issues/26
|
54
58
|
|
55
59
|
## Marginalia
|
56
60
|
|
57
|
-
This project is not developed by the Taskwarrior team. Obviously,
|
58
|
-
|
59
|
-
|
60
|
-
[![Build Status](https://secure.travis-ci.org/theunraveler/taskwarrior-web.png)](http://travis-ci.org/theunraveler/taskwarrior-web)
|
61
|
+
* This project is not developed by the Taskwarrior team. Obviously, taskwarrior-web extends Taskwarrior, but the projects are separate.
|
62
|
+
* `task-web` is mostly designed to run locally. As such, security is not of the highest priority. You may find that things such as CSRF protection are lacking. If things like this are important to you, please file an issue or a pull request.
|
data/lib/taskwarrior-web.rb
CHANGED
@@ -11,6 +11,7 @@ module TaskwarriorWeb
|
|
11
11
|
autoload :App, 'taskwarrior-web/app'
|
12
12
|
autoload :Helpers, 'taskwarrior-web/helpers'
|
13
13
|
autoload :Task, 'taskwarrior-web/model/task'
|
14
|
+
autoload :Annotation, 'taskwarrior-web/model/annotation'
|
14
15
|
autoload :Config, 'taskwarrior-web/model/config'
|
15
16
|
autoload :Command, 'taskwarrior-web/model/command'
|
16
17
|
autoload :CommandBuilder, 'taskwarrior-web/services/builder'
|
data/lib/taskwarrior-web/app.rb
CHANGED
@@ -40,14 +40,21 @@ class TaskwarriorWeb::App < Sinatra::Base
|
|
40
40
|
else
|
41
41
|
@tasks = TaskwarriorWeb::Task.find_by_status(params[:status])
|
42
42
|
end
|
43
|
-
|
44
|
-
|
43
|
+
|
44
|
+
case params[:status]
|
45
|
+
when ('pending' or 'waiting')
|
46
|
+
@tasks.sort_by! { |t| [-t.urgency.to_f, t.priority.nil?.to_s, t.priority.to_s, t.due.nil?.to_s, t.due.to_s, t.project.to_s] }
|
47
|
+
when ('completed' or 'deleted')
|
48
|
+
@tasks.sort_by! { |t| [Time.parse(t.end)] }.reverse!
|
49
|
+
end
|
50
|
+
|
51
|
+
erb :'tasks/index'
|
45
52
|
end
|
46
53
|
|
47
54
|
get '/tasks/new/?' do
|
48
55
|
@title = 'New Task'
|
49
56
|
@date_format = TaskwarriorWeb::Config.dateformat(:js) || 'm/d/yyyy'
|
50
|
-
erb :
|
57
|
+
erb :'tasks/new'
|
51
58
|
end
|
52
59
|
|
53
60
|
post '/tasks/?' do
|
@@ -60,7 +67,7 @@ class TaskwarriorWeb::App < Sinatra::Base
|
|
60
67
|
end
|
61
68
|
|
62
69
|
flash.now[:error] = @task._errors.join(', ')
|
63
|
-
erb :
|
70
|
+
erb :'tasks/new'
|
64
71
|
end
|
65
72
|
|
66
73
|
get '/tasks/:uuid/?' do
|
@@ -68,7 +75,7 @@ class TaskwarriorWeb::App < Sinatra::Base
|
|
68
75
|
@task = TaskwarriorWeb::Task.find(params[:uuid]) || not_found
|
69
76
|
@title = %(Editing "#{@task}")
|
70
77
|
@date_format = TaskwarriorWeb::Config.dateformat(:js) || 'm/d/yyyy'
|
71
|
-
erb :
|
78
|
+
erb :'tasks/edit'
|
72
79
|
end
|
73
80
|
|
74
81
|
patch '/tasks/:uuid/?' do
|
@@ -82,14 +89,7 @@ class TaskwarriorWeb::App < Sinatra::Base
|
|
82
89
|
end
|
83
90
|
|
84
91
|
flash.now[:error] = @task._errors.join(', ')
|
85
|
-
erb :
|
86
|
-
end
|
87
|
-
|
88
|
-
get '/tasks/:uuid/delete/?' do
|
89
|
-
not_found unless TaskwarriorWeb::Config.supports?(:editing)
|
90
|
-
@task = TaskwarriorWeb::Task.find(params[:uuid]) || not_found
|
91
|
-
@title = %(Are you sure you want to delete the task "#{@task}"?)
|
92
|
-
erb :delete_confirm
|
92
|
+
erb :'tasks/edit'
|
93
93
|
end
|
94
94
|
|
95
95
|
delete '/tasks/:uuid' do
|
@@ -100,21 +100,49 @@ class TaskwarriorWeb::App < Sinatra::Base
|
|
100
100
|
redirect to('/tasks')
|
101
101
|
end
|
102
102
|
|
103
|
+
# Annotations
|
104
|
+
get '/tasks/:uuid/annotations/new.?:format?' do
|
105
|
+
@task = TaskwarriorWeb::Task.find(params[:uuid]) || not_found
|
106
|
+
@json = params[:format] == 'json'
|
107
|
+
erb :'tasks/_annotation_form', :layout => !@json
|
108
|
+
end
|
109
|
+
|
110
|
+
post '/tasks/:uuid/annotations' do
|
111
|
+
@task = TaskwarriorWeb::Task.find(params[:uuid]) || not_found
|
112
|
+
|
113
|
+
annotation = TaskwarriorWeb::Annotation.new(params[:annotation])
|
114
|
+
if annotation.is_valid?
|
115
|
+
message = annotation.save!
|
116
|
+
flash[:success] = message.blank? ? %(Annotation was added to "#{@task}") : message
|
117
|
+
else
|
118
|
+
flash[:error] = annotation._errors.join(', ')
|
119
|
+
end
|
120
|
+
|
121
|
+
redirect back
|
122
|
+
end
|
123
|
+
|
124
|
+
delete '/tasks/:uuid/annotations/:description' do
|
125
|
+
@task = TaskwarriorWeb::Task.find(params[:uuid]) || not_found
|
126
|
+
TaskwarriorWeb::Annotation.new({ :task_id => @task.uuid, :description => params[:description] }).delete!
|
127
|
+
flash[:success] = %(Annotation was deleted from "#{@task}")
|
128
|
+
redirect back
|
129
|
+
end
|
130
|
+
|
103
131
|
# Projects
|
104
132
|
get '/projects/overview/?' do
|
105
133
|
@title = 'Projects'
|
106
134
|
@tasks = TaskwarriorWeb::Task.query('status.not' => :deleted, 'project.not' => '')
|
107
|
-
.sort_by! { |
|
108
|
-
.group_by { |
|
135
|
+
.sort_by! { |t| [-t.urgency.to_f, t.priority.nil?.to_s, t.priority.to_s, t.due.nil?.to_s, t.due.to_s] }
|
136
|
+
.group_by { |t| t.project.to_s }
|
109
137
|
.reject { |project, tasks| tasks.select { |task| task.status == 'pending' }.empty? }
|
110
|
-
erb :projects
|
138
|
+
erb :'projects/index'
|
111
139
|
end
|
112
140
|
|
113
141
|
get '/projects/:name/?' do
|
114
142
|
@title = unlinkify(params[:name])
|
115
|
-
@tasks = TaskwarriorWeb::Task.query('status.not' =>
|
116
|
-
.sort_by! { |
|
117
|
-
erb :
|
143
|
+
@tasks = TaskwarriorWeb::Task.query('status.not' => :deleted, :project => @title)
|
144
|
+
.sort_by! { |t| [-t.urgency.to_f, t.priority.nil?.to_s, t.priority.to_s, t.due.nil?.to_s, t.due.to_s] }
|
145
|
+
erb :'projects/show'
|
118
146
|
end
|
119
147
|
|
120
148
|
# Redirects
|
@@ -63,9 +63,11 @@ module TaskwarriorWeb::App::Helpers
|
|
63
63
|
|
64
64
|
def crud_links(task)
|
65
65
|
string = %(<span class="crud-links">)
|
66
|
+
string << %(<a class="annotation-add" href="/tasks/#{task.uuid}/annotations/new"><i class="icon-comment"></i></a>)
|
67
|
+
string << %( | )
|
66
68
|
string << %(<a href="/tasks/#{task.uuid}"><i class="icon-pencil"></i></a>)
|
67
69
|
string << %( | )
|
68
|
-
string << %(<a href="/tasks/#{task.uuid}
|
70
|
+
string << %(<a href="/tasks/#{task.uuid}" data-method="DELETE" data-confirm="Are you sure you want to delete this task?"><i class="icon-trash"></i></a>)
|
69
71
|
string << %(</span>)
|
70
72
|
string
|
71
73
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module TaskwarriorWeb
|
2
|
+
class Annotation
|
3
|
+
attr_accessor :task_id, :entry, :description, :_errors
|
4
|
+
|
5
|
+
def initialize(attributes = {})
|
6
|
+
attributes.each do |attr, value|
|
7
|
+
send("#{attr}=", value) if respond_to?(attr.to_sym)
|
8
|
+
end
|
9
|
+
|
10
|
+
@_errors = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def save!
|
14
|
+
Command.new(:annotate, self.task_id, { :description => self.description }).run
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete!
|
18
|
+
Command.new(:denotate, self.task_id, { :description => self.description }).run
|
19
|
+
end
|
20
|
+
|
21
|
+
def is_valid?
|
22
|
+
@_errors << 'You must provide a description' if self.description.blank?
|
23
|
+
@_errors.empty?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -7,8 +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, :remove_tags
|
11
|
-
alias :annotate= :annotations=
|
10
|
+
:urgency, :_errors, :remove_tags
|
12
11
|
|
13
12
|
####################################
|
14
13
|
# MODEL METHODS FOR INDIVIDUAL TASKS
|
@@ -21,6 +20,7 @@ module TaskwarriorWeb
|
|
21
20
|
|
22
21
|
@_errors = []
|
23
22
|
@tags = [] if @tags.nil?
|
23
|
+
@annotations = [] if @annotations.nil?
|
24
24
|
end
|
25
25
|
|
26
26
|
def save!
|
@@ -44,6 +44,15 @@ module TaskwarriorWeb
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
# Create annotation instances.
|
48
|
+
def annotations=(annotations)
|
49
|
+
@annotations = []
|
50
|
+
annotations.each do |annotation|
|
51
|
+
annotation.merge({ :task_id => self.uuid })
|
52
|
+
@annotations << Annotation.new(annotation)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
47
56
|
def is_valid?
|
48
57
|
@_errors << 'You must provide a description' if self.description.blank?
|
49
58
|
@_errors.empty?
|
@@ -82,4 +82,6 @@ table.table thead .sorting_asc { background: url('../img/sort_asc.png') no-repea
|
|
82
82
|
table.table thead .sorting_desc { background: url('../img/sort_desc.png') no-repeat center right; }
|
83
83
|
|
84
84
|
table.table thead .sorting_asc_disabled { background: url('../img/sort_asc_disabled.png') no-repeat center right; }
|
85
|
-
table.table thead .sorting_desc_disabled { background: url('../img/sort_desc_disabled.png') no-repeat center right; }
|
85
|
+
table.table thead .sorting_desc_disabled { background: url('../img/sort_desc_disabled.png') no-repeat center right; }
|
86
|
+
|
87
|
+
#annotations-modal textarea { width: 100%; }
|
@@ -1,10 +1,12 @@
|
|
1
1
|
$(document).ready(function() {
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
initDatePicker();
|
3
|
+
initAutocomplete();
|
4
|
+
initTaskCompletion();
|
5
5
|
initHotkeys();
|
6
6
|
initTablesort();
|
7
|
-
|
7
|
+
initAnnotationsModal();
|
8
|
+
initUjs();
|
9
|
+
refreshDockBadge();
|
8
10
|
|
9
11
|
// Hack to account for navbar when clicking anchor links.
|
10
12
|
$('#sidebar .nav li a').click(function(event) {
|
@@ -119,6 +121,30 @@ var initTablesort = function() {
|
|
119
121
|
});
|
120
122
|
};
|
121
123
|
|
124
|
+
var initAnnotationsModal = function() {
|
125
|
+
$(document).on('click', 'a.annotation-add', function(event) {
|
126
|
+
event.preventDefault();
|
127
|
+
$.get($(this).attr('href') + '.json', function(data) {
|
128
|
+
$('#annotations-modal')
|
129
|
+
.html(data)
|
130
|
+
.modal('show');
|
131
|
+
});
|
132
|
+
});
|
133
|
+
};
|
134
|
+
|
135
|
+
var initUjs = function() {
|
136
|
+
$('[data-method]').click(function(e) {
|
137
|
+
e.preventDefault();
|
138
|
+
var link = $(this);
|
139
|
+
if (confirm(link.data('confirm') || 'Are you sure?')) {
|
140
|
+
$('<form action="' + link.attr('href') + '" method="POST" style="display: none;">')
|
141
|
+
.append('<input type="hidden" name="_method" value="' + link.data('method') + '" />')
|
142
|
+
.insertAfter(link)
|
143
|
+
.submit();
|
144
|
+
}
|
145
|
+
});
|
146
|
+
};
|
147
|
+
|
122
148
|
// Count updating.
|
123
149
|
|
124
150
|
var refreshDockBadge = function() {
|
@@ -143,7 +169,10 @@ var refreshSubnavCount = function() {
|
|
143
169
|
* @param string [severity] The severity of the message.
|
144
170
|
*/
|
145
171
|
function set_message(msg, severity) {
|
146
|
-
$('<div style="display: none;" class="alert
|
172
|
+
$('<div style="display: none;" class="alert">')
|
173
|
+
.addClass('alert-' + (severity || 'success'))
|
174
|
+
.append('<button type="button" class="close" data-dismiss="alert">×</button>')
|
175
|
+
.append(msg)
|
147
176
|
.appendTo('#flash-messages')
|
148
177
|
.fadeIn();
|
149
178
|
}
|
@@ -8,6 +8,8 @@ module TaskwarriorWeb::CommandBuilder::Base
|
|
8
8
|
:delete => 'rc.confirmation=no :id delete',
|
9
9
|
:query => TaskwarriorWeb::Config.version > Versionomy.parse('1.9.2') ? '_query' : 'export',
|
10
10
|
:complete => ':id done',
|
11
|
+
:annotate => ':id annotate',
|
12
|
+
:denotate => ':id denotate',
|
11
13
|
:projects => '_projects',
|
12
14
|
:tags => '_tags'
|
13
15
|
}
|
@@ -16,10 +16,10 @@
|
|
16
16
|
<body data-spy="scroll" data-offset="60" data-target="#sidebar">
|
17
17
|
<div id="wrap">
|
18
18
|
<div id="page" class="container">
|
19
|
-
<%= erb :_topbar %>
|
20
|
-
<%= erb :_subnav %>
|
19
|
+
<%= erb :'partials/_topbar' %>
|
20
|
+
<%= erb :'partials/_subnav' %>
|
21
21
|
<section class="content">
|
22
|
-
<%= erb :_flash %>
|
22
|
+
<%= erb :'partials/_flash' %>
|
23
23
|
<%= yield %>
|
24
24
|
</section>
|
25
25
|
</div>
|
@@ -27,9 +27,9 @@
|
|
27
27
|
</div>
|
28
28
|
<div id="footer">
|
29
29
|
<div class="container muted">
|
30
|
-
<%= erb :_footer %>
|
30
|
+
<%= erb :'partials/_footer' %>
|
31
31
|
</div>
|
32
32
|
</div>
|
33
|
-
<%= erb :_hotkeys %>
|
33
|
+
<%= erb :'partials/_hotkeys' %>
|
34
34
|
</body>
|
35
35
|
</html>
|
@@ -1,6 +1,7 @@
|
|
1
1
|
<div id="flash-messages">
|
2
2
|
<% flash_types.select{ |severity| flash.has?(severity) }.each do |severity| %>
|
3
3
|
<div class="alert alert-<%= severity %>">
|
4
|
+
<button type="button" class="close" data-dismiss="alert">×</button>
|
4
5
|
<%= flash[severity] %>
|
5
6
|
</div>
|
6
7
|
<% end %>
|
File without changes
|
@@ -1,7 +1,7 @@
|
|
1
|
-
<div id="hotkeys" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="
|
1
|
+
<div id="hotkeys" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="hotkeys-modal-label" aria-hidden="true">
|
2
2
|
<div class="modal-header">
|
3
3
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
4
|
-
<h3 id="
|
4
|
+
<h3 id="hotkeys-modal-label">Hotkeys</h3>
|
5
5
|
</div>
|
6
6
|
<div class="modal-body">
|
7
7
|
<p>TaskwarriorWeb includes hotkeys for quick navigation to commonly-used parts of the application.</p>
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<form action="/tasks/<%= @task.uuid %>/annotations" method="POST" class="modal-form">
|
2
|
+
<div class="modal-header">
|
3
|
+
<% if @json %>
|
4
|
+
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
5
|
+
<% end %>
|
6
|
+
<h3 id="annotations-modal-label">Add annotation to "<%= @task %>"</h3>
|
7
|
+
</div>
|
8
|
+
<div class="modal-body">
|
9
|
+
<textarea name="annotation[description]" placeholder="New annotation..." required="required"></textarea>
|
10
|
+
<input type="hidden" name="annotation[task_id]" value="<%= @task.uuid %>" />
|
11
|
+
</div>
|
12
|
+
<div class="modal-footer">
|
13
|
+
<% if @json %>
|
14
|
+
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
15
|
+
<% end %>
|
16
|
+
<input type="submit" id="annotations-modal-save" class="btn btn-primary" value="Save annotation" />
|
17
|
+
</div>
|
18
|
+
</form>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<div class="control-group">
|
2
2
|
<label for="task-description" class="control-label">Description</label>
|
3
3
|
<div class="controls">
|
4
|
-
<input type="textfield" id="task-description" name="task[description]" value="<%= @task.description unless @task.nil? %>" />
|
4
|
+
<input type="textfield" required="required" id="task-description" name="task[description]" value="<%= @task.description unless @task.nil? %>" />
|
5
5
|
</div>
|
6
6
|
</div>
|
7
7
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<form id="new-task-form" class="form-horizontal" action="/tasks/<%= @task.uuid %>" method="post">
|
2
2
|
<input type="hidden" name="task[uuid]" value="<%= @task.uuid %>" />
|
3
3
|
|
4
|
-
<%= erb :
|
4
|
+
<%= erb :'tasks/_form' %>
|
5
5
|
|
6
6
|
<div class="control-group">
|
7
7
|
<div class="controls">
|
@@ -22,16 +22,20 @@
|
|
22
22
|
</thead>
|
23
23
|
<tbody>
|
24
24
|
<% @tasks.each do |task| %>
|
25
|
-
<tr class="
|
25
|
+
<tr<%= %{ class="#{colorize_date(task.due)}"} if params[:status] == 'pending' %>>
|
26
26
|
<% if params[:status] == 'pending' %>
|
27
27
|
<td><input type="checkbox" class="complete" data-task-id="<%= task.uuid %>" /></td>
|
28
28
|
<% end %>
|
29
29
|
<td>
|
30
30
|
<%= task.description %>
|
31
|
-
<% unless task.annotations.
|
31
|
+
<% unless task.annotations.empty? %>
|
32
32
|
<ul>
|
33
33
|
<% task.annotations.each do |annotation| %>
|
34
|
-
<li
|
34
|
+
<li>
|
35
|
+
<%= format_date(annotation.entry) %>: <%= auto_link(annotation.description) %>
|
36
|
+
|
37
|
+
<a href="/tasks/<%= task.uuid %>/annotations/<%= ERB::Util.u(annotation.description) %>" data-method="DELETE" data-confirm="Are you sure you want to delete this annotation?"><i class="icon-trash"></i></a>
|
38
|
+
</li>
|
35
39
|
<% end %>
|
36
40
|
</ul>
|
37
41
|
<% end %>
|
@@ -47,3 +51,8 @@
|
|
47
51
|
</table>
|
48
52
|
<% end %>
|
49
53
|
</div>
|
54
|
+
|
55
|
+
<% if can_edit %>
|
56
|
+
<div id="annotations-modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="annotations-modal-label" aria-hidden="true">
|
57
|
+
</div>
|
58
|
+
<% end %>
|
data/spec/app/app_spec.rb
CHANGED
@@ -157,35 +157,6 @@ describe TaskwarriorWeb::App do
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
-
describe 'GET /tasks/:uuid/delete' do
|
161
|
-
context 'given a non-existant task' do
|
162
|
-
it 'should return a 404' do
|
163
|
-
TaskwarriorWeb::Task.should_receive(:find).and_return(nil)
|
164
|
-
get '/tasks/429897527/delete'
|
165
|
-
last_response.should be_not_found
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
context 'given an existing task' do
|
170
|
-
before do
|
171
|
-
TaskwarriorWeb::Task.should_receive(:find).and_return(
|
172
|
-
TaskwarriorWeb::Task.new({:uuid => 246, :description => 'Test task with a longer description'})
|
173
|
-
)
|
174
|
-
get '/tasks/246/delete'
|
175
|
-
end
|
176
|
-
|
177
|
-
it 'should show a delete form' do
|
178
|
-
last_response.body.should have_tag('form', :with => { :action => '/tasks/246', :method => 'post' }) do
|
179
|
-
with_tag('input', :with => { :name => '_method', :value => 'delete' })
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
it 'should display a delete button' do
|
184
|
-
last_response.body.should have_tag('input', :with => { :type => 'submit', :value => 'Delete' })
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
160
|
describe 'DELETE /tasks/:uuid' do
|
190
161
|
context 'given a non-existant task' do
|
191
162
|
it 'should return a 404' do
|
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.1.
|
4
|
+
version: 1.1.8
|
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:
|
12
|
+
date: 2013-01-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sinatra
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: parseconfig
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: vegas
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: '0'
|
44
54
|
type: :runtime
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: rinku
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
@@ -54,10 +69,15 @@ dependencies:
|
|
54
69
|
version: '0'
|
55
70
|
type: :runtime
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: versionomy
|
60
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
61
81
|
none: false
|
62
82
|
requirements:
|
63
83
|
- - ! '>='
|
@@ -65,10 +85,15 @@ dependencies:
|
|
65
85
|
version: '0'
|
66
86
|
type: :runtime
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
69
94
|
- !ruby/object:Gem::Dependency
|
70
95
|
name: activesupport
|
71
|
-
requirement:
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
72
97
|
none: false
|
73
98
|
requirements:
|
74
99
|
- - ! '>='
|
@@ -76,10 +101,15 @@ dependencies:
|
|
76
101
|
version: '0'
|
77
102
|
type: :runtime
|
78
103
|
prerelease: false
|
79
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
80
110
|
- !ruby/object:Gem::Dependency
|
81
111
|
name: sinatra-simple-navigation
|
82
|
-
requirement:
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
83
113
|
none: false
|
84
114
|
requirements:
|
85
115
|
- - ! '>='
|
@@ -87,10 +117,15 @@ dependencies:
|
|
87
117
|
version: '0'
|
88
118
|
type: :runtime
|
89
119
|
prerelease: false
|
90
|
-
version_requirements:
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
91
126
|
- !ruby/object:Gem::Dependency
|
92
127
|
name: rack-flash3
|
93
|
-
requirement:
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
94
129
|
none: false
|
95
130
|
requirements:
|
96
131
|
- - ! '>='
|
@@ -98,10 +133,15 @@ dependencies:
|
|
98
133
|
version: '0'
|
99
134
|
type: :runtime
|
100
135
|
prerelease: false
|
101
|
-
version_requirements:
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
102
142
|
- !ruby/object:Gem::Dependency
|
103
143
|
name: rake
|
104
|
-
requirement:
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
105
145
|
none: false
|
106
146
|
requirements:
|
107
147
|
- - ! '>='
|
@@ -109,10 +149,15 @@ dependencies:
|
|
109
149
|
version: '0'
|
110
150
|
type: :development
|
111
151
|
prerelease: false
|
112
|
-
version_requirements:
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
113
158
|
- !ruby/object:Gem::Dependency
|
114
159
|
name: rack-test
|
115
|
-
requirement:
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
116
161
|
none: false
|
117
162
|
requirements:
|
118
163
|
- - ! '>='
|
@@ -120,10 +165,15 @@ dependencies:
|
|
120
165
|
version: '0'
|
121
166
|
type: :development
|
122
167
|
prerelease: false
|
123
|
-
version_requirements:
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
124
174
|
- !ruby/object:Gem::Dependency
|
125
175
|
name: rspec
|
126
|
-
requirement:
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
127
177
|
none: false
|
128
178
|
requirements:
|
129
179
|
- - ! '>='
|
@@ -131,10 +181,15 @@ dependencies:
|
|
131
181
|
version: '0'
|
132
182
|
type: :development
|
133
183
|
prerelease: false
|
134
|
-
version_requirements:
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ! '>='
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
135
190
|
- !ruby/object:Gem::Dependency
|
136
191
|
name: rspec-html-matchers
|
137
|
-
requirement:
|
192
|
+
requirement: !ruby/object:Gem::Requirement
|
138
193
|
none: false
|
139
194
|
requirements:
|
140
195
|
- - ! '>='
|
@@ -142,7 +197,12 @@ dependencies:
|
|
142
197
|
version: '0'
|
143
198
|
type: :development
|
144
199
|
prerelease: false
|
145
|
-
version_requirements:
|
200
|
+
version_requirements: !ruby/object:Gem::Requirement
|
201
|
+
none: false
|
202
|
+
requirements:
|
203
|
+
- - ! '>='
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
146
206
|
description: This gem provides a graphical frontend for the Taskwarrior task manager.
|
147
207
|
It is based on Sinatra.
|
148
208
|
email:
|
@@ -166,6 +226,7 @@ files:
|
|
166
226
|
- lib/taskwarrior-web/app.rb
|
167
227
|
- lib/taskwarrior-web/config/navigation.rb
|
168
228
|
- lib/taskwarrior-web/helpers.rb
|
229
|
+
- lib/taskwarrior-web/model/annotation.rb
|
169
230
|
- lib/taskwarrior-web/model/command.rb
|
170
231
|
- lib/taskwarrior-web/model/config.rb
|
171
232
|
- lib/taskwarrior-web/model/task.rb
|
@@ -200,19 +261,19 @@ files:
|
|
200
261
|
- lib/taskwarrior-web/services/runner.rb
|
201
262
|
- lib/taskwarrior-web/version.rb
|
202
263
|
- lib/taskwarrior-web/views/404.erb
|
203
|
-
- lib/taskwarrior-web/views/_flash.erb
|
204
|
-
- lib/taskwarrior-web/views/_footer.erb
|
205
|
-
- lib/taskwarrior-web/views/_hotkeys.erb
|
206
|
-
- lib/taskwarrior-web/views/_subnav.erb
|
207
|
-
- lib/taskwarrior-web/views/_task_form.erb
|
208
|
-
- lib/taskwarrior-web/views/_topbar.erb
|
209
|
-
- lib/taskwarrior-web/views/delete_confirm.erb
|
210
|
-
- lib/taskwarrior-web/views/edit_task.erb
|
211
264
|
- lib/taskwarrior-web/views/layout.erb
|
212
|
-
- lib/taskwarrior-web/views/
|
213
|
-
- lib/taskwarrior-web/views/
|
214
|
-
- lib/taskwarrior-web/views/
|
215
|
-
- lib/taskwarrior-web/views/
|
265
|
+
- lib/taskwarrior-web/views/partials/_flash.erb
|
266
|
+
- lib/taskwarrior-web/views/partials/_footer.erb
|
267
|
+
- lib/taskwarrior-web/views/partials/_hotkeys.erb
|
268
|
+
- lib/taskwarrior-web/views/partials/_subnav.erb
|
269
|
+
- lib/taskwarrior-web/views/partials/_topbar.erb
|
270
|
+
- lib/taskwarrior-web/views/projects/index.erb
|
271
|
+
- lib/taskwarrior-web/views/projects/show.erb
|
272
|
+
- lib/taskwarrior-web/views/tasks/_annotation_form.erb
|
273
|
+
- lib/taskwarrior-web/views/tasks/_form.erb
|
274
|
+
- lib/taskwarrior-web/views/tasks/edit.erb
|
275
|
+
- lib/taskwarrior-web/views/tasks/index.erb
|
276
|
+
- lib/taskwarrior-web/views/tasks/new.erb
|
216
277
|
- spec/app/app_spec.rb
|
217
278
|
- spec/app/helpers_spec.rb
|
218
279
|
- spec/files/taskrc
|
@@ -246,10 +307,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
246
307
|
version: '0'
|
247
308
|
segments:
|
248
309
|
- 0
|
249
|
-
hash: -
|
310
|
+
hash: -4275568887696200084
|
250
311
|
requirements: []
|
251
312
|
rubyforge_project: taskwarrior-web
|
252
|
-
rubygems_version: 1.8.
|
313
|
+
rubygems_version: 1.8.23
|
253
314
|
signing_key:
|
254
315
|
specification_version: 3
|
255
316
|
summary: Web frontend for taskwarrior command line task manager.
|