org-ql
org-ql copied to clipboard
Agenda entries are missing properties necessary for view filtering
For agenda entries generated by an org-ql-block query, the entries themselves are missing a few properties necessary for filtering the agenda view using Org's built-in functionality. For example, org-agenda-filter-by-effort expects a txt property for each entry and org-agenda-filter-by-category can't find the necessary category at the current point. For fixing filtering by effort, you can advise org-ql-view--format-element to inject the required txt property (which in turn has the necessary effort-minutes property):
(defun my/org-ql-view--format-element (orig-fun &rest args)
(if (not args)
""
(let* ((element args)
(properties (cadar element))
(result (apply orig-fun element))
(effort (org-entry-get (plist-get properties :org-marker) "Effort"))
(effort-minutes (if effort (org-duration-to-minutes effort) nil))
;; Attempts to emulate the txt properties of each entry. Only sets
;; effort-minutes.
(txt (if effort-minutes
(propertize "dummy" 'effort-minutes effort-minutes)
"dummy")))
(org-add-props result (list 'txt txt)))))
(advice-add 'org-ql-view--format-element :around #'my/org-ql-view--format-element)
Ideally, we would be able to reuse whatever Org does to set these properties and set what is necessary for the filtering commands that don't work (as far as I can tell it's only by effort and category).
Also potentially related to https://github.com/alphapapa/org-ql/issues/294 which mentions the missing txt property.
Yes, as the comment here says:
https://github.com/alphapapa/org-ql/blob/131407814ebfd8d409f23bc5cceeeb2b5da1a8d9/org-ql-view.el#L821-L823
Patches to remedy that shortcoming are welcome, as long as they don't impact performance too badly.
OTOH, for this specific example, it would almost seem more sensible to adjust the search query to account for the effort or category. After all, filtering results after the search is equivalent to adjusting the query to return more specific results in the first place. Implementing filtering on top of searching seems like spending effort to implement two different ways of doing the same thing.
I agree, I think the fact that org-ql already allows filtering by category and effort probably doesn't make this issue too important to address. My use case is also a little bit obscure: from a single org-ql query, I'd like to quickly filter entries based on their efforts, which org-agenda-filter-by-effort has a UI to let you do so. Re-using that UI instead of building something to interactively edit the query seemed like the easiest thing to do. At the very least, having entries behave more consistently with org-generated entries would be nice.
Also, for category, it seems like Org just uses the property org-category.
Well, I can see how additional quick filtering could be useful, so I'm not opposed to supporting it, given the conditions I mentioned. Thanks.
I also encountered this issue. My use case is to generate an agenda and filter by category.
My agenda covers many projects, each in its own category. I thus like to filter the agenda by category. Native agenda allows for this, while agenda generated by org-ql-block does not.
In the past I was using org's native tags-todo to build my agenda, but org-ql syntax is much more transparent. It also allows for more complex stuck projects that fit my needs much better :-)
I described the filtering issue in a Reddit Post.
Following alphapapa's suggestion, I modified the code in org-ql-view--format-element, also adding category in the output list like so (I guessed at the format):
(--> string
;; FIXME: Use proper prefix
(concat " " it)
(org-add-props it properties
'org-agenda-type 'search
'category category ; <----- MV mod ***
'todo-state todo-keyword
'tags tag-list
'org-habit-p habit-property))
That did not enable editing by category: categories were not present in the block agenda.
@mirkov Org uses org-category instead of just category, so you probably need to use that property instead (you can do C-u C-x = on a regular agenda entry to see all the properties that Org sets).
This is what I've been using to add support for filtering by category. It also adds effort and timestamp date type:
(defun my/org-ql-view--format-element (orig-fun &rest args)
"This function will intercept the original function and
add the effort and category to the result.
ARGS is `element' in `org-ql-view--format-element'"
(if (not args)
""
(let* ((element args)
(properties (cadar element))
(result (apply orig-fun element))
(effort (org-entry-get (plist-get properties :org-marker) "Effort"))
;; XXX: Category might already be included in the plist.
(category (org-entry-get (plist-get properties :org-marker) "CATEGORY"))
(effort-minutes (if effort (org-duration-to-minutes effort) nil))
;; Attempts to emulate the txt properties of each entry. Only sets
;; effort-minutes.
(txt (if effort-minutes
(propertize "dummy" 'effort-minutes effort-minutes)
"dummy"))
(ts-date-pair (org-with-point-at (plist-get properties :org-marker)
(org-agenda-entry-get-agenda-timestamp (point))))
(ts-date (car ts-date-pair))
;; This string looks something like " scheduled". It is meant to be
;; concatted with a type to make something like "todo scheduled", but
;; we only care about the "scheduled" part.
(ts-date-type (cdr ts-date-pair)))
(org-add-props result
(list 'txt txt
'org-category category
'ts-date ts-date
'type ts-date-type)))))