omniboard 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/HISTORY.md +71 -0
- data/README.md +404 -0
- data/Rakefile +3 -0
- data/bin/omniboard +43 -0
- data/lib/omniboard.rb +25 -0
- data/lib/omniboard/colour.rb +15 -0
- data/lib/omniboard/column.rb +368 -0
- data/lib/omniboard/columns/active.rb +17 -0
- data/lib/omniboard/columns/backburner.rb +5 -0
- data/lib/omniboard/columns/completed.rb +5 -0
- data/lib/omniboard/columns/config.rb +11 -0
- data/lib/omniboard/core_ext.rb +22 -0
- data/lib/omniboard/group.rb +104 -0
- data/lib/omniboard/omniboard.rb +149 -0
- data/lib/omniboard/project_wrapper.rb +119 -0
- data/lib/omniboard/property.rb +53 -0
- data/lib/omniboard/renderer.rb +50 -0
- data/lib/omniboard/styled_text.rb +63 -0
- data/lib/omniboard/styled_text_element.rb +40 -0
- data/lib/omniboard/templates/column.erb +25 -0
- data/lib/omniboard/templates/postamble.erb +226 -0
- data/lib/omniboard/templates/preamble.erb +346 -0
- data/lib/omniboard/templates/project.erb +15 -0
- data/omniboard.gemspec +23 -0
- data/version.txt +1 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2e2d60b99706bc348ecdf70a1e4f1851346f0316
|
4
|
+
data.tar.gz: a38acea769d7d5cfb9baa852816970dd1f462096
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1e0fadb02d7333a293538b4f342cf9a7da530d75052f55524ab642b8e1eaeef01575aa0ee8e112b0c32dd9b781e975667d27c1bba24c9c2f8183444097581ae9
|
7
|
+
data.tar.gz: c84e7be8a6a55cf2e0e4f5ffff26f0655959e5400e0fc2767c2f3da7198b6fc2c7de0f7f09ccc95dd20ba34ff30fee897ec5ad55f2989b872d5cf05050a3af85
|
data/HISTORY.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# 1.1.1 // 2016-09-09
|
2
|
+
|
3
|
+
Fixed an issue with core column classes. Plus some handy debugging stuff!
|
4
|
+
|
5
|
+
* [New] `Omniboard::Column.reset_columns` allows you to wipe the global register of columns. Useful for unit testing.
|
6
|
+
* [New] `Omniboard::Column.reset_config` now takes the option `:all` to wipe all configuration fields.
|
7
|
+
* [Fix] The `config.rb` template file will now let you have projects that are not contained within folders.
|
8
|
+
|
9
|
+
# 1.1.0 // 2016-08-29
|
10
|
+
|
11
|
+
Add custom CSS to your omniboard.
|
12
|
+
|
13
|
+
* [New] You can now add custom CSS to your board. Any CSS in the file `custom.css` (inside your config file) will be included in the output HTML file. See the readme for more information.
|
14
|
+
|
15
|
+
# 1.0.1 // 2016-08-01
|
16
|
+
|
17
|
+
* [Fix] Fixing CDATA tags within javascript - allows me to parse as XHTML while keeping JS all good.
|
18
|
+
* [Fix] Improved display of column header numbers.
|
19
|
+
|
20
|
+
# 1.0.0 // 2016-07-08
|
21
|
+
|
22
|
+
Hopefully integrating all the little changes, bugfixes, and modifications that I've wanted to do for a while.
|
23
|
+
|
24
|
+
* [New] `Omniboard::document=` is available if you just want to set Omniboard's document variable by yourself without all that hassle of loading from file.
|
25
|
+
* [New] If your document has no fetcher, it's always considered to be at head.
|
26
|
+
* [New] Substantial changes to how groups work. You may now return any object from a `group_by` method, and use that object to sort your groups before displaying names. See the Readme for more information on how to use the updated groups.
|
27
|
+
* [New] You can now custom colour your groups! See the Readme for more information.
|
28
|
+
* [New] The column's `icon` methods may now return an array of `[icon, alt]`, for supplying popup information on icons.
|
29
|
+
* [New] You can add a "refresh" link to the top of the page using the `refresh_link` property inside `config`.
|
30
|
+
* [New] Setting `hide_dimmed` on a column will automatically hide dimmed projects on page load
|
31
|
+
* [New] Set project counts using the `display_project_counts` property on columns. Can be set to `all`, `active`, or `marked`.
|
32
|
+
|
33
|
+
# 0.4.0 // 2016-06-27
|
34
|
+
|
35
|
+
Updates galore! Well, some updates, anyway. While there are some larger underlying problems with the codebase, I've just been focussing on the notes of each project.
|
36
|
+
|
37
|
+
* [New] Project notes will now show basic styling (italics, bold, underline; better paragraphs).
|
38
|
+
* [New] Added some shiny CSS for the project details - notes and remaining tasks lists should be a bit sexier
|
39
|
+
* [New] Projects now show due and deferral dates (when appropriate) in the project overlay
|
40
|
+
|
41
|
+
# 0.3.3 // 2016-05-23
|
42
|
+
|
43
|
+
Wow, it's been some time, hasn't it? Let's add updates to this.
|
44
|
+
|
45
|
+
* [New] Omniboard works out when your document is out of date, or even when it's become detached from the head of your omnifocus database, and lets you know.
|
46
|
+
* [Fix] `Group` now has a default `light_colour` method - no more errors if you don't group your projects!
|
47
|
+
|
48
|
+
|
49
|
+
# 0.3.1 // 2016-02-13
|
50
|
+
|
51
|
+
* [Fix] Remove console.log() debugging in js functions
|
52
|
+
* [Fix] Previous change to hide/show code resulted in a non-functioning info overlay. Now fixed.
|
53
|
+
|
54
|
+
# 0.3.0 // 2016-02-12
|
55
|
+
|
56
|
+
* [New] You can now set a block property to `nil` to avoid running any block (including any defaults).
|
57
|
+
|
58
|
+
# 0.2.1 // 2016-02-09
|
59
|
+
|
60
|
+
* [Fix] Added `trollop` to list of runtime dependencies
|
61
|
+
|
62
|
+
# 0.2.0 // 2016-02-08
|
63
|
+
|
64
|
+
A number of updates around the board
|
65
|
+
|
66
|
+
* [New] Project groups will hide themselves if every child project has been hidden.
|
67
|
+
* [New] Added `Column#filter_button`, which allows you to add a button filtering out dimmed tasks.
|
68
|
+
|
69
|
+
# 0.1.0 // 2016-02-04
|
70
|
+
|
71
|
+
Hello, world!
|
data/README.md
ADDED
@@ -0,0 +1,404 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/jyruzicka/omniboard.svg?branch=master)](https://travis-ci.org/jyruzicka/omniboard)
|
2
|
+
|
3
|
+
Omniboard is a static kanban webpage generator for OmniFocus. Use it to view your currently active projects as a kanban board, with custom sorting and grouping options.
|
4
|
+
|
5
|
+
# You will need
|
6
|
+
|
7
|
+
* Ruby 2.0 or later: type `ruby -v` at the terminal to see if you have it.
|
8
|
+
* It helps to know a little ruby if you want to customise your columns.
|
9
|
+
* Omniboard uses the `rubyfocus` gem, which requires Apple Developer Tools to install.
|
10
|
+
|
11
|
+
# Installing
|
12
|
+
|
13
|
+
Omniboard comes as a gem, although it's not currently hosted on rubygems or the like.
|
14
|
+
|
15
|
+
```
|
16
|
+
git clone https://github.com/jyruzicka/omniboard.git
|
17
|
+
cd omniboard
|
18
|
+
gem build omniboard.gemspec
|
19
|
+
gem install omniboard-1.1.1.gem
|
20
|
+
```
|
21
|
+
|
22
|
+
Alternatively, add it to your `Gemfile`:
|
23
|
+
|
24
|
+
```
|
25
|
+
gem "omniboard", git: "https://github.com/jyruzicka/omniboard.git"
|
26
|
+
```
|
27
|
+
|
28
|
+
# Running
|
29
|
+
|
30
|
+
Once installed, use the built-in binary:
|
31
|
+
|
32
|
+
```
|
33
|
+
omniboard
|
34
|
+
```
|
35
|
+
|
36
|
+
To see the possible flags, run:
|
37
|
+
|
38
|
+
```
|
39
|
+
omniboard --help
|
40
|
+
```
|
41
|
+
|
42
|
+
## Flags
|
43
|
+
|
44
|
+
* **--configure**: By default, omniboard stores its configuration information in `~/.omniboard`. You can change this with the `configure` option, specifying a different folder.
|
45
|
+
* **--output**: `omniboard` normally outputs to STDOUT. Give a value here to direct its output to a file.
|
46
|
+
* **--reset**: If you pass this flag, `omniboard` will clear its cache and fetch a new copy of the OmniFocus database.
|
47
|
+
|
48
|
+
## Columns
|
49
|
+
|
50
|
+
Your omniboard is made up a number of *columns*, with each column made up of a number of different projects from OmniFocus.
|
51
|
+
|
52
|
+
The first time you run `omniboard`, you will generate a configuration folder at `~/.omniboard/`. You can find two types of files in your configuration folder: first, a database file (which stores the current cached state of OmniFocus), and second, a series of configuration and column files, all maintained within a folder named `columns`.
|
53
|
+
|
54
|
+
You can create a new column in your Kanban by creating a new file in the `columns` folder. Name it whatever you like, but make sure that it ends with `.rb`. Inside, you configure a column using the following syntax:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
Omniboard::Column.new "Column name" do
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
You should also find a file called `config.rb`. This is where you can place global configuration values.
|
62
|
+
|
63
|
+
### Customising columns
|
64
|
+
|
65
|
+
You can customise your columns in all manner of ways. These methods either govern how the column is displayed, or which projects will end up in there.
|
66
|
+
|
67
|
+
The following column properties are numeric or symbols. You can alter these inside the column block in the following manner:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
Omniboard::Column.new "Sample column" do
|
71
|
+
order 1
|
72
|
+
display :compact
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
* **order**: A number indicating where this column fits on the kanban board. The lower a column's order, the further to the left of the board it'll appear. This defaults to 0.
|
77
|
+
* **display**: A column whose display is `:compact` will only show a summary of each project contained within it. A column whose display is `:full` will show additional details for each project. By default, a column's display is `:full`.
|
78
|
+
* **width**: The relative width of this column as compared to other columns on the board. The column's default width is 0.
|
79
|
+
* **columns**: The number of sub-columns within this column. If `columns` is greater than 1, projects will be displayed side-by-side. By default, each column's width is 1.
|
80
|
+
* **filter_button**: Whether or not to show a small button which, when clicked, will hide all "dimmed" projects. By default, set to false.
|
81
|
+
* **hide_dimmed**: When set to true, dimmed projects will be automatically hidden on page load. By default, set to false.
|
82
|
+
* **display_project_counts**: Set this to `:all`, `:active`, or `:marked`. Will display the total number of projects in a column: the value you give it will determine if it counts all projects (`:all`), projects which are not dimmed (`:active`), or only marked projected (`:marked`).
|
83
|
+
* **project_limit**: If you're display project counts and you have more projects than this number, the project count will show up highlighted red. Useful if you're trying to keep down your total number of active projects!
|
84
|
+
|
85
|
+
The following column properties take blocks of ruby code. You can alter these inside the column block in the following manner:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
Omniboard::Column.new "Active projects only" do
|
89
|
+
|
90
|
+
conditions do |p|
|
91
|
+
p.active?
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
* **conditions**: This block is run on every project in OmniFocus, with the project being passed in as the first argument. If the block returns true, the project is included in this column. If it returns false, the project is not shown in this column.
|
97
|
+
* **sort**: This block determines the order in which projects appear within groups. `sort` may take one argument, in which case it acts much like ruby's [`sort_by`](http://ruby-doc.org/core-2.3.0/Enumerable.html#method-i-sort_by) method, or two arguments, in which case it acts like ruby's [`sort`](http://ruby-doc.org/core-2.3.0/Enumerable.html#method-i-sort) method. If no sort block is provided, the projects are sorted by name. The arguments passed to `sort` are the projects to be compared when sorting.
|
98
|
+
* **mark_when**: Marked projects are given a small red "bookmark" in the top-right-hand corner of their ticket. Marked projects are those which, when passed to the `marked_when` block, return true.
|
99
|
+
* **dim_when**: Dimmed projects are shown at partial opacity, and can be useful for providing information on less critical projects, or those that are currently deferred. Dimmed projects are those which, when passed to the `dim_when` block, return true.
|
100
|
+
* **icon**: This block is run on every project, and if it returns a non-`nil` value, omniboard will place a small icon in the bottom-right-hand corner of the project ticket with an image source set to the return value of the `icon` block. For example, if the `icon` block returns "waiting.png" for a project, omniboard will place a small icon in the bottom-right corner of the project ticket with the source equal to "waiting.png". Alternatively, you may use one of the two pre-defined SVG icons bundled into omniboard by setting the icon to either "svg:hanging" or "svg:waiting-on".
|
101
|
+
|
102
|
+
### Grouping projects
|
103
|
+
|
104
|
+
You may want to group your projects - for example, by parent folder, by flagged status, or by due date. Each column may group its projects in different ways, or you may assign one default grouping method to be used over the whole board.
|
105
|
+
|
106
|
+
Each group is associated with an *identifier* - this could be an object, a true/false value, a string, whatever you want. You can use the `group_by` method to set this identifier:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
Omniboard::Column.new "Due soon" do
|
110
|
+
group_by{ |p| p.due.to_date - Date.today }
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
This will group each project by how many days in the future it's due. The identifier will be an integer.
|
115
|
+
|
116
|
+
You can sort groups as well, using the `sort_groups` method:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
Omniboard::Column.new "Due soon" do
|
120
|
+
group_by{ |p| p.due.to_date - Date.today }
|
121
|
+
sort_groups{ |i| i }
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
The `sort_groups` block takes arguments in the same way that `sort` does, although the arguments passed to the block are the identifiers of the relevant groups.
|
126
|
+
|
127
|
+
It's nice to have fancy names for your groups, and sometimes they'll be a little more involved than just the string representations of the group identifiers. You can set groups' names using the `group_name` block. Again, it gets passed the identifier for each group, and returns the string name of the group:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
Omniboard::Column.new "Due soon" do
|
131
|
+
group_by{ |p| p.due.to_date - Date.today }
|
132
|
+
sort_groups{ |i| i }
|
133
|
+
|
134
|
+
group_name{ |i| "Due in " + (i == 1 ? "1 day" : "#{i} days") }
|
135
|
+
end
|
136
|
+
```
|
137
|
+
|
138
|
+
By default, each group is given an arbitrary colour. Sometimes you might want to override that. You can do this with the `colour_group` method. Note that you set this globally using the `Omniboard::Column.config` method (see next section for more on this):
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
Omniboard::Column.config do
|
142
|
+
colour_group(50){ |i| i == 0 }
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
The `colour_group` method takes two arguments: first, a numerical value which represents the *hue* you want the group to be, and a block which is evaluated by passing the group's identifier and receiving `true` or `false`. So in this example, if the identifier is equal to 0, the group's colour is set to 50.
|
147
|
+
|
148
|
+
### Global configuration
|
149
|
+
|
150
|
+
You may apply global configuration properties by the following code:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
Omniboard::Column.config do
|
154
|
+
# Config values here...
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
The majority of the column properties listed above can be applied inside of `Omniboard::Column.config` as well, giving a resulting **global value**. How omniboard uses this value depends on the property in question:
|
159
|
+
|
160
|
+
* A global `conditions` block will be run *in addition to* a column-specific `conditions` block on each project. The project must return `true` in **both cases** in order to be displayed in the given column. This way, a global `conditions` block effectively acts as a board-wide filter.
|
161
|
+
* A global `sort`, `group_by`, `sort_groups`, `group_name`, `mark_when`, `dim_when`, `hide_dimmed`, or `icon` block will be run *if no column-specific block is provided* on a given column. This way, a global block for any of these properties effectively acts as a "global default".
|
162
|
+
|
163
|
+
You can also set the following configuration options:
|
164
|
+
|
165
|
+
* `heading_font`: Tells omniboard to use a particular font for headings (`h1`, `h2`, etc.). This may be a CSS-style list of fonts. Defaults to "Helvetica, Arial, sans-serif".
|
166
|
+
* `body_font`: Tells omniboard to use a particular font for body text. Defaults to "Helvetica, Arial, sans-serif".
|
167
|
+
* `refresh_link`: If set, will put a refresh symbol in the title, which allows you to call a given URL. If you're running this in Sinatra + Pow, for example, you can call a path that will auto-refresh your database for you. Note that this usually requires a bit of complex setup - mess with this as you wish!
|
168
|
+
|
169
|
+
### Countering global configurations
|
170
|
+
|
171
|
+
You may find yourself in a situation where you want to have a default group block for every column except one, which you would prefer to leave ungrouped. In this case, you can specify "no value" (overriding the column default) by setting the property to nil:
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
Omniboard::Column.new "Don't group me" do
|
175
|
+
group_by nil
|
176
|
+
end
|
177
|
+
```
|
178
|
+
|
179
|
+
## Custom CSS
|
180
|
+
|
181
|
+
You can also change the look and feel of your kanban board by customising the CSS. All changes go into the file `custom.css`, stored in your Omniboard folder (by default, in `~/.omniboard`).
|
182
|
+
|
183
|
+
# Case studies
|
184
|
+
|
185
|
+
That's quite a lot to take in, so let's have a look at some of the ways I use this system.
|
186
|
+
|
187
|
+
## Leaving out folders
|
188
|
+
### Leaving out an entire single folder
|
189
|
+
|
190
|
+
I have a bunch of template projects for use in Chris Sauve's amazing [Templates.scpt](http://cmsauve.com/projects/templates/). There's no point in displaying these on my kanban board, so instead I'll block them using a global `conditions` block.
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
Omniboard::Column.config do
|
194
|
+
conditions do |p|
|
195
|
+
!p.contained_within?(name: "Template")
|
196
|
+
end
|
197
|
+
end
|
198
|
+
```
|
199
|
+
|
200
|
+
This block will return true only if the project is **not** contained within a folder that has the name "Template".
|
201
|
+
|
202
|
+
### Leaving out an entire folder including all subfolders
|
203
|
+
|
204
|
+
Sometimes you want to leave out an entire folder including all subfolders. For example, when your folder "Template" also has subfolders such as "Work Projects", "Private Things" or if you add additional subfolders or rename existing subfolders from time to time. The easiest way to block all subfolders as well:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
Omniboard::Column.config do
|
208
|
+
conditions do |p|
|
209
|
+
!p.ancestry.any?{ |c| c.name == "Template" }
|
210
|
+
end
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
## Mark based on a note's contents
|
215
|
+
|
216
|
+
I use projects' note fields to highlight my important projects that I want to focus on right now. Using a global `mark_when` block, I can make sure that projects I've flagged in this way always show up marked.
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
Omniboard::Column.config do
|
220
|
+
mark_when do |p|
|
221
|
+
p.note && p.note.include?("@flagged")
|
222
|
+
end
|
223
|
+
end
|
224
|
+
```
|
225
|
+
|
226
|
+
## Group & sort based on folders
|
227
|
+
|
228
|
+
I like to see my projects grouped by their parent folders, but they're sometimes buried two or three folders deep. Since group names really need to be strings, I can format group names right inside the block.
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
Omniboard::Column.config do
|
232
|
+
group_by do |p|
|
233
|
+
if p.ancestry == []
|
234
|
+
"Top level"
|
235
|
+
else
|
236
|
+
p.ancestry.map(&:name).reverse.join("→")
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
```
|
241
|
+
|
242
|
+
Note that `Project#ancestry` is a method that returns an array of the project's containing folders, up to the Document level. If the project has no containing folder, we just give it the group "Top level". If we just wanted to group based on the top-most folder, we could do something like the following:
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
Omniboard::Column.config do
|
246
|
+
group_by do |p|
|
247
|
+
if p.ancestry == []
|
248
|
+
"Top level"
|
249
|
+
else
|
250
|
+
p.ancestry.last.name
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
```
|
255
|
+
|
256
|
+
If we want to sort these folders nicely, we could do something like the following:
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
Omniboard::Column.config do
|
260
|
+
sort_groups do |x,y|
|
261
|
+
if x == "Top level"
|
262
|
+
-1
|
263
|
+
elsif y == "Top level"
|
264
|
+
1
|
265
|
+
else
|
266
|
+
x <=> y
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
```
|
272
|
+
|
273
|
+
This means that a group with the name "Top level" appears at the top of the column; after this groups are displayed in alphabetical order.
|
274
|
+
|
275
|
+
## Displaying a "backburner" column
|
276
|
+
|
277
|
+
I have a compacted column on the left of my Kanban board showing all the projects that are on hold or that have been deferred at the project level. The column's config looks like this:
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
Omniboard::Column.new "Backburner" do
|
281
|
+
|
282
|
+
conditions do |p|
|
283
|
+
p.on_hold? || p.deferred?
|
284
|
+
end
|
285
|
+
|
286
|
+
order 0
|
287
|
+
|
288
|
+
display :compact
|
289
|
+
end
|
290
|
+
```
|
291
|
+
|
292
|
+
## Displaying an "active projects" column
|
293
|
+
|
294
|
+
My main column is quite large, taking up twice as much space as regular columns. The projects are displayed as full tickets, with four projects per row:
|
295
|
+
|
296
|
+
```ruby
|
297
|
+
Omniboard::Column.new "In Progress" do
|
298
|
+
order 1
|
299
|
+
width 2
|
300
|
+
columns 4
|
301
|
+
display :full
|
302
|
+
```
|
303
|
+
|
304
|
+
Only projects which get through the global filter, and are marked "active" in OmniFocus, are shown:
|
305
|
+
|
306
|
+
```
|
307
|
+
conditions do |p|
|
308
|
+
p.active?
|
309
|
+
end
|
310
|
+
```
|
311
|
+
|
312
|
+
## Dim a task when you can't do anything
|
313
|
+
|
314
|
+
I have a custom context "Waiting for..." which marks tasks I'm waiting to hear from others on. When all available tasks are "Waiting for..." tasks, I can't do anything, so I might as well dim the project.
|
315
|
+
|
316
|
+
```ruby
|
317
|
+
dim_when do |p|
|
318
|
+
p.next_tasks.all? { |t| t.context && t.context.name == "Waiting for..." }
|
319
|
+
end
|
320
|
+
```
|
321
|
+
|
322
|
+
I'd also like to sort these tasks to the end of my projects in each group:
|
323
|
+
|
324
|
+
```ruby
|
325
|
+
sort do |p|
|
326
|
+
if p.next_tasks.all?{ |t| t.context && t.context.name == "Waiting for..." }
|
327
|
+
1
|
328
|
+
else
|
329
|
+
0
|
330
|
+
end
|
331
|
+
end
|
332
|
+
```
|
333
|
+
|
334
|
+
## Show an icon for a given context
|
335
|
+
|
336
|
+
In fact, I could mark these "Waiting for..." projects with an icon, just so I know *why* they're dimmed.
|
337
|
+
|
338
|
+
```ruby
|
339
|
+
icon do |p|
|
340
|
+
if p.next_tasks.all?{ |t| t.context && t.context.name == "Waiting for..." }
|
341
|
+
"waiting.png"
|
342
|
+
end
|
343
|
+
end
|
344
|
+
```
|
345
|
+
|
346
|
+
## Filter by date
|
347
|
+
|
348
|
+
What if you want to filter by defer, due, or completion date? For example:
|
349
|
+
|
350
|
+
* A "due soon" column containing only projects due within the next week.
|
351
|
+
* The "completed" column only shows projects you completed in the last two days.
|
352
|
+
* An "upcoming" column which shows projects which are currently deferred, but whose next action is deferred until tomorrow.
|
353
|
+
|
354
|
+
Before I start on this, I'd like to quickly talk about project vs. task due dates. OmniFocus treats each project as a sub-class of a task, with a couple of extra properties. This means that any property you can assign to a task, you can (in theory) assign to a project. This means that a project can be marked "deferred" for two reasons:
|
355
|
+
|
356
|
+
* The project itself is deferred, or
|
357
|
+
* Every available task in the project is deferred.
|
358
|
+
|
359
|
+
Similarly, it's a good idea to consider the due date on both tasks within a project, and the project itself.
|
360
|
+
|
361
|
+
For our first trick, let's consider a column containing projects whose due date is within the next week. Every task has a `due` property which returns a `Time` or `nil`:
|
362
|
+
|
363
|
+
```ruby
|
364
|
+
one_week_from_now = Time.now + (60 * 60 * 24 * 7)
|
365
|
+
|
366
|
+
Omniboard::Column.new "Due soon" do
|
367
|
+
conditions do |p|
|
368
|
+
p.active? && p.due && p.due <= one_week_from_now
|
369
|
+
end
|
370
|
+
end
|
371
|
+
```
|
372
|
+
|
373
|
+
This checks the project's `due` property, and if it's not null (and is less than one week from now), includes it in the board. We also filter out on-hold, completed, or dropped projects.
|
374
|
+
|
375
|
+
The "completed" column is pretty similar:
|
376
|
+
|
377
|
+
```ruby
|
378
|
+
one_week_ago = Time.now - (60 * 60 * 24 * 7)
|
379
|
+
|
380
|
+
Omniboard::Column.new "Completed" do
|
381
|
+
conditions do |p|
|
382
|
+
p.completed? && p.completed >= one_week_ago
|
383
|
+
end
|
384
|
+
end
|
385
|
+
```
|
386
|
+
|
387
|
+
Note that any completed task or project should always have a set completion time, so we don't need to check if the `completed` property is `nil`. You could, just to be double-sure.
|
388
|
+
|
389
|
+
Finally, let's look at our "upcoming" column. This is a bit trickier because we're delving into per-task dates, but it's still surprisingly easy to do. One thing I'm going to do here is say that the project's available tasks just need to be deferred to *any* time tomorrow, not within 24 hours of this exact moment.
|
390
|
+
|
391
|
+
```ruby
|
392
|
+
tomorrow = Date.today + 1
|
393
|
+
|
394
|
+
Omniboard::Column.new "Starting tomorrow" do
|
395
|
+
conditions do |p|
|
396
|
+
p.actionable_tasks.size == 0 && # No tasks we can do right now
|
397
|
+
p.next_tasks.any?{ |t| t.start.to_date == tomorrow } # Incomplete, non-blocked task starting tomorrow
|
398
|
+
end
|
399
|
+
end
|
400
|
+
```
|
401
|
+
|
402
|
+
# Feedback and further information
|
403
|
+
|
404
|
+
If you have any examples of particularly good examples of column configuration, or think I've missed something in the case studies or documentation, get in touch!
|