# File note TODO states

**URL:** <https://org-roam.discourse.group/t/file-note-todo-states/1821>\
**Category:** How To\
**Created:** [July 24, 2021, 8:14pm UTC](https://org-roam.discourse.group/t/file-note-todo-states/1821 "2021-07-24T20:14:22Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![agibragimov](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/agibragimov/32/589_2.png) [@agibragimov](https://org-roam.discourse.group/u/agibragimov)\
**Post date:** [July 24, 2021, 8:14pm UTC](https://org-roam.discourse.group/t/file-note-todo-states/1821/1 "2021-07-24T20:14:22Z")

</div>

I just learned about a few handy functions org-roam-node struct adds:  
`org-roam-node-todo`, `org-roam-node-scheduled`, `org-roam-node-properties`, etc.

It allows you to read some info about an Org-roam-node, e.g.:  
`(org-roam-node-scheduled (org-roam-node-at-point))`

How is this useful?  
So, you can, for example, find all the nodes that are in “TODO”, like so:

```auto
(org-roam-node-find nil nil (lambda (node)
                              (string-equal "TODO" (org-roam-node-todo node))))

```

Now, the problem is: That works only for nodes that are Org headings.  
It doesn’t seem to work with nodes that are note files.

I can’t figure out a way to toggle TODO state for the entire file, I tried adding the property:

```auto
:PROPERTIES:
:ID: 48632DFE-8945-48C4-B101-430179FC79AA
:TODO: TODO
:END:
#+title: Some title

```

That didn’t work because `(org-entry-properties)` doesn’t even see it. So my question is:

**How do I set properties like TODO state, SCHEDULED and DEADLINE for the entire Org-roam node?**

---

<div class="post-metadata">

**Author:** ![jethro](https://avatars.discourse-cdn.com/v4/letter/j/b5a626/32.png) [@jethro](https://org-roam.discourse.group/u/jethro)\
**Post date:** [July 25, 2021, 3:31am UTC](https://org-roam.discourse.group/t/file-note-todo-states/1821/2 "2021-07-25T03:31:06Z")

</div>

You cannot, unfortunately. These are exclusively for headline nodes, since Org doesn’t provide syntax for this in the top-level files.

---

<div class="post-metadata">

**Author:** ![alanz](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/alanz/32/717_2.png) [@alanz](https://org-roam.discourse.group/u/alanz)\
**Post date:** [July 25, 2021, 2:50pm UTC](https://org-roam.discourse.group/t/file-note-todo-states/1821/3 "2021-07-25T14:50:19Z")

</div>

There is a [blog post about managing TODO items in org-roam files](https://magnus.therning.org/2021-07-23-keeping-todo-items-in-org-roam-v2.html) that might help.

---

<div class="post-metadata">

**Author:** ![agibragimov](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/agibragimov/32/589_2.png) [@agibragimov](https://org-roam.discourse.group/u/agibragimov)\
**Post date:** [July 25, 2021, 8:40pm UTC](https://org-roam.discourse.group/t/file-note-todo-states/1821/4 "2021-07-25T20:40:45Z")

</div>

Whoa, this is perfect. Basically, one can use `#+filetags: TODO` and the little snippet I posted has to be updated, and you can find all the nodes (either file notes or headings) with TODO, like so:

```auto
(org-roam-node-find
 nil nil
 (lambda (node)
   (or (string-equal "TODO" (org-roam-node-todo node))
       (seq-contains-p (org-roam-node-tags node) "TODO"))))

```

---

<div class="post-metadata">

**Author:** ![magthe](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/magthe/32/851_2.png) [@magthe](https://org-roam.discourse.group/u/magthe)\
**Post date:** [July 26, 2021, 4:47am UTC](https://org-roam.discourse.group/t/file-note-todo-states/1821/5 "2021-07-26T04:47:37Z")

</div>

I’m glad you’re finding use for it. I’d love to hear of any other improvements and adjustments you make.

---

<div class="post-metadata">

**Author:** ![agibragimov](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/agibragimov/32/589_2.png) [@agibragimov](https://org-roam.discourse.group/u/agibragimov)\
**Post date:** [July 26, 2021, 5:53am UTC](https://org-roam.discourse.group/t/file-note-todo-states/1821/6 "2021-07-26T05:53:35Z")

</div>

> I’d love to hear of any other improvements and adjustments you make

Of course. Here’s what I did:

- I wrote a function to toggle TODO states in note-files
- Advised org-todo function, now, it is possible to toggle TODO state with `C-c C-t`, and not only in the headings, but also the note-files
- Improved “find-nodes-with-todo-state”

Here’s the full set of functions, sorry @magthe, I slightly changed the names of those awesome helpers you wrote (for consistency with the rest of my config)

```auto
(require 'dash)

;; filetag helpers borrowed from:
;; https://magnus.therning.org/2021-07-23-keeping-todo-items-in-org-roam-v2.html

(defun org-roam/get-filetags ()
  (split-string (or (org-roam-get-keyword "filetags") "")))

(defun org-roam/add-filetag (tag)
  (let* ((new-tags (cons tag (org-roam/get-filetags)))
         (new-tags-str (combine-and-quote-strings new-tags)))
    (org-roam-set-keyword "filetags" new-tags-str)))

(defun org-roam/kill-filetag (tag)
  (let* ((new-tags (seq-difference (org-roam/get-filetags) `(,tag)))
         (new-tags-str (combine-and-quote-strings new-tags)))
    (org-roam-set-keyword "filetags" new-tags-str)))

(defun org-roam/org-todo-keywords->list ()
  (let ((lst (-partition-by
              (lambda (s) (string-equal s "|"))
              (seq-map
               (lambda (s) (replace-regexp-in-string "\(.*" "" s))
               (cl-rest (car org-todo-keywords))))))
    `(,(car lst) ,(caddr lst))))

(defun org-roam/find-nodes-with-todo-state (todo-state)
  "Finds all nodes with selected TODO state.
   For headings that would be regular Org-mode TODO cookie,
   for file notes it's managed with TODO filetag."
  (interactive "P")
  (let ((todo-state (or todo-state
                        (completing-read
                         "Choose TODO state"
                         (-flatten (org-roam/org-todo-keywords->list))))))
    (org-roam-node-find
     nil nil
     (lambda (node)
       (or (string-equal todo-state (org-roam-node-todo node))
           (seq-contains-p (org-roam-node-tags node) todo-state)
           (seq-contains-p (org-roam-node-tags node) todo-state))))))

(defun org-roam/toggle-todo-state-in-node (&optional new-state)
  "Togggle TODO filetag in Org-roam node file."
  (interactive "P")
  (when (and (not (active-minibuffer-window))
             (org-roam-file-p))
    (let* ((all-states (-flatten (org-roam/org-todo-keywords->list)))
           (new-state (or new-state
                          (completing-read "Choose TODO state" all-states)))
           (current (seq-find
                     (lambda (tag)
                       (seq-contains-p all-states tag))
                     (org-roam/get-filetags))))
      (when current (org-roam/kill-filetag current))
      (when (not (string-equal current new-state))
        (org-roam/add-filetag new-state)))))

(defun org-todo--around (old-fn &rest args)
  (if (and (not (active-minibuffer-window))
           (org-roam-file-p)
           (not (ignore-errors (org-get-outline-path 'with-self?))))
      (funcall 'org-roam/toggle-todo-state-in-node)
    (apply old-fn args)))

(advice-add 'org-todo :around #'org-todo--around)

```

Thanks to your initial idea, I was able to take my TODO-fu to another level 🙂

This entire snippet is “fresh out of the press”; please let me know if I’ve missed something (most likely I have)

---

<div class="post-metadata">

**Author:** ![agibragimov](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/agibragimov/32/589_2.png) [@agibragimov](https://org-roam.discourse.group/u/agibragimov)\
**Post date:** [July 26, 2021, 5:34pm UTC](https://org-roam.discourse.group/t/file-note-todo-states/1821/7 "2021-07-26T17:34:58Z")

</div>

Before this, I used a few Org-roam Nodes named: TODO 1, ONGOING, DONE, CANCELLED, and I’d add a link to a node (to designate its todo state).  
And then, to find all nodes that are in “TODO” state, I would navigate to the `* TODO` heading and toggle backlinks buffer.  
That’s pretty straightforward, simple, very “Org-Roamy” and has some benefits, like for example you can see all the items that are in todo state as a sub-section in the graph.

But this new approach with filetags and vanilla Org todo states feels a bit more ergonomic.

Of course, the austere simplicity of Org mode allows you to automate it and use both these ways, i.e., whenever you toggle TODO state (with `C-c C-t`) - it would add/remove/change link to the relevant todo state Org-Roam node.

I’m not sure now if I end up using both ways, or would stick to one. But it’s nice to have different ways.

* * *

- 1 Actually, Org wouldn’t let me create a heading named “TODO”, so I used a different name and addded `:roam_alises: TODO`
