gizmomogwai / org-kanban

Kanban table for org-mode

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

GTD states and org-kanban

Ypot opened this issue · comments

commented

I am a GTD user, and GTD states seem to be incompatible with "Kanban states".
If there were some idea to reconcile GTD and Kanban states, I would like to hear it.

Maybe instead of TODO states, could Properties be the table columns? or maybe by tags?

I love this work you did!

Hi @Ypot, could you elaborate more about what GTD means for you in org mode? Do you have an example how you use org mode for that?
The only thing that I can say right now is, that org modes TODO keywords are not fixed, you can specify them yourself, and org-kanban also uses those then.

A quick google search found me: https://orgmode.org/worg/org-gtd-etc.html but your workflow looks probably different.

org-kanban also can restrict the table to certain tags (but it still uses the org mode keywords (that default to TODO and DONE)).

commented

Hi @gizmomogwai!

GTD states are quite rigid. They usually are: PROJECT, NEXT, MAYBE, WAITING.

KANBAN columns are more flexible, and relative to the productive process.

So, I'd say a hard user of GTD hardly could use org-kanban, because its columns are already determined by GTD states.

Ok ... but what would you like to show in a table (not matter if you now call it kanban table or not)?
e.g. if you would start your org-mode files with #+TODO: PROJECT NEXT MAYBE WAITING
then you could see whats all in your NEXT column ... perhaps you can also create a table that only shows you the tasks that are tagged with the GTD things for a project? Is this even a thing in GTD or do you just have one GTD thingy for everything?

Do you have an example on how your GTD in org-mode looks at the moment, and what you would like to show in a table?

commented

An example I was working on.
GTD:
***** WAITING Cuba PPH

***** NEXT Línea Zinc-Níquel

KANBAN:

  • MANUFACTURING Cuba PPH
  • DRAWING Línea Zinc-Níquel

A dynamic block where I try to reconcile both (ignore the first ITEM):
imagen

***** WAITING Cuba PPH
:PROPERTIES:
:DISEÑO: [ ]
:HECHO-DISEÑO: [ ]
:FABRICACIÓN: [X]
:HECHO-FABRICACIÓN: [ ]
:FACTURACIÓN: [ ]
:FINALIZADO: [ ]
:END:
***** NEXT Línea Zinc Niquel
:PROPERTIES:
:DISEÑO: [X]
:HECHO-DISEÑO: [ ]
:FABRICACIÓN: [ ]
:HECHO-FABRICACIÓN: [ ]
:FACTURACIÓN: [ ]
:FINALIZADO: [ ]
:END:

Mhh .. .thanks for the example. Not sure that I understand that though.
Is it so, that Cuba is at the moment Waiting, whereas Linea is next and at the same time those are in manufactoring or drawing? so you have the gtd things in place to just see what you can do next and what is blocked and so on, and somewhere else you have the kind of details, e.g. if its blocked in a very early stage (e.g. on the drawing board) or if its blocked in the manufactoring?

commented

Cuba is at the moment Waiting, whereas Linea is next and at the same time those are in manufactoring or drawing?

Exactly. Different methodologies, different states. Not related necessarily.

so you have the gtd things in place to just see what you can do next and what is blocked and so on

Exactly. GTD is a personal organization method, there I can see what I can do NEXT and what is blocked (WAITING).

and somewhere else you have the kind of details, e.g. if its blocked in a very early stage (e.g. on the drawing board) or if its blocked in the manufactoring?

No. That is my trial to add those tasks to a KANBAN board. DRAWING or MANUFACTURING are not related to GTD states. They are pure and solely KANBAN states which I have tried to show using PROPERTIES.

commented

Where there is an [X], ideally should be the task (the ITEM)

Ok ... I think now I understand (at least a little bit your initial remarks).
You would have the TODO keywords in org-mode map to your personal GTD methology. But those you would not want to show an a table, instead you want to show for all tasks something else in the table (e.g. taken from properties or tags or something that just works :) ) ...

Would it work for you to flip that around? Meaning the GTD things seem to be much coarser and perhaps an org-agenda that just shows you all tasks that are tagged with WAITING would be enough for you ... I also imagine, that you would not move tasks around that often on GTD level.

e.g.

#+TODO: Drawing Manufactoring Shipping | Done

* Manufactoring toyboat                                             :WAITING:
* Drawing toyplane                                                     :NEXT:
* Done toycar                                                      :FINISHED:
* Shipping toyroller                                                :WAITING:

then org-agenda < m WAITING shows you all tasks that are waiting ... i wonder if there is a dynamic block for that as well...

commented

Thanks @gizmomogwai !

I must think about it, that's not a minor change for my workflow! As I suppose it wouldn't be easy either for org-kanban.

Best regards!!!

or one could use columnview dynamic blocks besides a org-kanban block to get the overview

#+TODO: Drawing Manufactoring Shipping | Done

* Manufactoring toyboat                                             :WAITING:
* Drawing toyplane                                                     :NEXT:
* Done toycar                                                      :FINISHED:
* Shipping toyroller                                                :WAITING:

#+BEGIN: kanban :mirrored t
| Done   | Shipping  | Manufactoring | Drawing  |
|--------+-----------+---------------+----------|
|        |           | [[file:test.org::*toyboat][toyboat]]       |          |
|        |           |               | [[file:test.org::*toyplane][toyplane]] |
| [[file:test.org::*toycar][toycar]] |           |               |          |
|        | [[file:test.org::*toyroller][toyroller]] |               |          |
#+END:

#+BEGIN: columnview :match "NEXT|WAITING" :id global
| ITEM      | TODO          | PRIORITY | TAGS      |
|-----------+---------------+----------+-----------|
| toyboat   | Manufactoring | B        | :WAITING: |
| toyplane  | Drawing       | B        | :NEXT:    |
| toyroller | Shipping      | B        | :WAITING: |
#+END:

Thanks @gizmomogwai !

I must think about it, that's not a minor change for my workflow! As I suppose it wouldn't be easy either for org-kanban.

Best regards!!!

for org-kanban itself i think it would be rather hard, as its really interacting with the keywords.
Just one last question ... the kanban keywords (either implemented as tags or properties or something else), would they also have an order like the todo keywords? Or are they just tags (one element could even have two tags at the same time?)

fun fact ... my emacs installation has just 3 kinds of dynamic blocks: clocktable, org-kanban and columnview :/

https://github.com/alphapapa/org-ql seems to be quite capable ...
I imagine another dblock that takes e.g. a list of tags as input (and transforms them into a table headers) should be quite easy to hack together. would you also want to interact with the table rows?

commented

Thanks @gizmomogwai !
I must think about it, that's not a minor change for my workflow! As I suppose it wouldn't be easy either for org-kanban.
Best regards!!!

for org-kanban itself i think it would be rather hard, as its really interacting with the keywords. Just one last question ... the kanban keywords (either implemented as tags or properties or something else), would they also have an order like the todo keywords? Or are they just tags (one element could even have two tags at the same time?)

Yes, Kanban, as I understand it, must have an order in its columns, example: Backlog, Ready, In Progress, and Delivered. I think an item shouldn't have more than one "kanban state" at the same time.

fun fact ... my emacs installation has just 3 kinds of dynamic blocks: clocktable, org-kanban and columnview :/

Not mine, just 2! xD

https://github.com/alphapapa/org-ql seems to be quite capable ... I imagine another dblock that takes e.g. a list of tags as input (and transforms them into a table headers) should be quite easy to hack together. would you also want to interact with the table rows?

I saw it, I will have to study how to use org-ql, or its advantages over dynamic blocks. Thanks :-)

Not sure if it would be necessary to interact with the table rows. I will know after using it ;D

Thanks for your help!

I came up with this small snippet

(defun org-tagged//map ()
  ""
  (list
    (nth 4 (org-heading-components))
    (s-chop-right 1 (s-chop-left 1 (nth 5  (org-heading-components))))))

(defun org-tagged//row-for (todo tags)
  "TODO is a list of heading and tag (only one tag allowed).
TAGS are all tags interesting for the table."
  (let*
    (
      (heading (nth 0 todo))
      (tag (nth 1 todo))
      (index (-elem-index tag tags))
      (prefix (s-repeat (1+ index) "|"))
      (suffix (s-repeat (- (length tags) index) "|"))
      )
    (format "%s%s%s" prefix heading suffix)))
(defun org-dblock-write:tagged (params)
  "Create a tagged dynamic block.
PARAMS must contain: `:tags`."
  (insert
    (let*
      (
        (tags (s-split "|" (plist-get params :tags)))
        (table-title (s-join "|" tags))
        (todos (org-map-entries 'org-tagged//map table-title))
        (row-for (lambda (todo) (org-tagged//row-for todo tags)))
        (table (s-join "\n" (-map row-for todos)))
        )
      (format "|%s|\n|--|\n%s" table-title table)))
  (org-table-align))

which leads to something like this:

#+TODO: Drawing Manufactoring Shipping | Done

* Manufactoring toyboat                                             :WAITING:
* Drawing toyplane                                                     :NEXT:
* Done toycar                                                      :FINISHED:
* Shipping toyroller                                                :WAITING:

#+BEGIN: kanban :mirrored t
| Done   | Shipping  | Manufactoring | Drawing  |
|--------+-----------+---------------+----------|
|        |           | [[file:test.org::*toyboat][toyboat]]       |          |
|        |           |               | [[file:test.org::*toyplane][toyplane]] |
| [[file:test.org::*toycar][toycar]] |           |               |          |
|        | [[file:test.org::*toyroller][toyroller]] |               |          |
#+END:

#+BEGIN: tagged :tags "WAITING|NEXT"
| WAITING   | NEXT     |
|-----------+----------|
| toyboat   |          |
|           | toyplane |
| toyroller |          |
#+END:

#+BEGIN: columnview :match "NEXT|WAITING" :id global
| ITEM      | TODO          | PRIORITY | TAGS      |
|-----------+---------------+----------+-----------|
| toyboat   | Manufactoring | B        | :WAITING: |
| toyplane  | Drawing       | B        | :NEXT:    |
| toyroller | Shipping      | B        | :WAITING: |
#+END:

with this you can select exactly (by tags) the elements you want and they are rendered in a table (the tagged dynamic block).

if you have interest in that, i could also package that up as a melpa package ... or just the small snippet for you to adjust and put in your init.el?

commented

if you have interest in that, i could also package that up as a melpa package ... or just the small snippet for you to adjust and put in your init.el?

This looks nice!

#+BEGIN: tagged :tags "WAITING|NEXT"
| WAITING   | NEXT     |
|-----------+----------|
| toyboat   |          |
|           | toyplane |
| toyroller |          |
#+END:

Give me some time to try it.

commented

if you have interest in that, i could also package that up as a melpa package ... or just the small snippet for you to adjust and put in your init.el?

This looks nice!

#+BEGIN: tagged :tags "WAITING|NEXT"
| WAITING   | NEXT     |
|-----------+----------|
| toyboat   |          |
|           | toyplane |
| toyroller |          |
#+END:

Give me some time to try it.

I am trying to reproduce a table like that, but I don't know how to use your code :/
I have evaluated it, but I can't run the functions you defined :/

You do not run them, org-mode runs them for you. You can evaluate the 3 functions so that emacs loads them, then you can somewhere in an org file insert the begin tabbed end lines of the dynamic block and then Press ctrl-c ctrl-c when the cursor is on begin.

commented

I tried it, this should work after evaluating the code, and pressing C-c C-c in the dynamic block, I suppose?:

imagen

Probably its best, if you put all functions i sent to you e.g. into the scratch buffer and evaluate them there ...
if the functions are in the org buffer, org might not be too happy with it.
I will try to package the dynamic block this evening as melpa package or at least upload it (including tests) to github.

one thing, that needs to change (probably in my implementation) is, that atm i only can handle one tag ...
looks like you use already kanban as tag to select on the items. perhaps it would be better to put the state into properties (as you did in the beginning). for that the implementation would need to change slightly!

mhh .. i also changed it now, so that several tags are supported (although the table only looks at the first one). so something like :tag1:kanban: should work, whereas :kanban:tag1: would not sort the element in tag1. what do you think?

commented

mhh .. i also changed it now, so that several tags are supported (although the table only looks at the first one). so something like :tag1:kanban: should work, whereas :kanban:tag1: would not sort the element in tag1. what do you think?

I like that!
I think it could be less inconvenience than using properties, although maybe veteran users could think differently.

Will it be possible to move the elements in the table and automatically it to change the first tag?

Not sure yet .. would be a future feature I guess .. i would first like to come up with something that works for you. Would you like to have x es in the columns where a tag is set or the heading?

commented

Xs were a workaround. The lay-out should be like this of yours:

imagen

commented

You are getting to something like this, but better (I found it from your readme.org):
imagen

BUT there you can see that "Product Story 2" is outdated (tag is wrong or column is wrong).

I see ... and would there always be only one tag of the table applied to a todo? or could it be, that sometimes its more tags?
Nonetheless ... will try to prepare something. Do you always have the tables in the same org file as the tasks themselves? or do we also need something like in org-kanban, where several files can be includeded?

commented

would there always be only one tag of the table applied to a todo? or could it be, that sometimes its more tags?

Not sure if I understand... For example a tag :InProgress: and a tag :gizmomogwai:? Not sure, could you do in the easiest way for you, and after that we'll see?

Do you always have the tables in the same org file as the tasks themselves? or do we also need something like in org-kanban, where several files can be includeded?

My trial was with columnview and id in the same org file. I only use one file for tasks, that would be enough.

ok ... i now have a "new" version that works only with tags ...

code:

(require 's)
(require 'dash)
(require 'org)
(require 'org-table)

(defun org-tagged//map ()
  "Map one todoitem to the needed information.
Return a list with
- the heading
- the tags as list of strings."
  (list
    (nth 4 (org-heading-components))
    (remove "" (s-split ":" (nth 5 (org-heading-components))))))

(defun org-tagged//row-for (heading item-tags tags)
  "Create a row for a HEADING and its ITEM-TAGS for a table with TAGS."
  (format "|%s|" (s-join "|" (-map (lambda (tag)
                      (if (-elem-index tag item-tags) heading "")) tags))))

(defun org-tagged/version ()
  "Print org-tagge version."
  (interactive)
  (message "org-tagged 0.0.1"))

;;;###autoload
(defun org-dblock-write:tagged (params)
  "Create a tagged dynamic block.
PARAMS must contain: `:tags`."
  (insert
    (let*
      (
        (tags (s-split "|" (plist-get params :tags)))
        (table-title (plist-get params :tags))
        (todos (org-map-entries 'org-tagged//map (plist-get params :match)))
        (row-for (lambda (todo) (org-tagged//row-for (nth 0 todo) (nth 1 todo) tags)))
        (table (s-join "\n" (-map row-for todos)))
        )
      (format "|%s|\n|--|\n%s" table-title table)))
  (org-table-align))
(provide 'org-tagged)

example output:

* TODO todo1_1                                                  :tag1:tag2:kanban:
* TODO todo2_2                                                  :tag2:kanban:
* DONE todo3_2                                                         :tag2:
* DONE todo4_1                                                         :tag1:
* TODO todo5_3                                                         :tag3:
* DONE todo6_3                                                         :tag3:

#+BEGIN: tagged :tags "tag1|tag2|tag3" :match "kanban"
| tag1    | tag2    | tag3 |
|---------+---------+------|
| todo1_1 | todo1_1 |      |
|         | todo2_2 |      |
#+END:

the idea is, that now you can select item with :match according to https://orgmode.org/guide/Matching-Tags-and-Properties.html and then you can create a table for them for :tags ... if by chance one element has two tags of the table its shown twice. so there is almost no semantic on the tags!

commented

Ehm... you did it, no words. Thanks, now I will try it at work. THANKS!

imagen

The demo.org:

#+TODO: Todo Plan Develop Test Done
#+STARTUP: showall

  • Todo Task One :urgent:
  • Plan Two :starred:
  • Develop Three :InProgress:kanban:
  • Test Four
    ** Test Four1 :starred:kanban:
    ** Test Four2 :starred:kanban:
  • Done Five
  • Kanban
    #+BEGIN: tagged :tags "starred|urgent|InProgress" :match "kanban"
    | starred | urgent | InProgress |
    |---------+--------+------------|
    | | | Three |
    | Four1 | | |
    | Four2 | | |
    #+END:

#+begin_src emacs-lisp
(require 's)
(require 'dash)
(require 'org)
(require 'org-table)

(defun org-tagged//map ()
"Map one todoitem to the needed information.
Return a list with

  • the heading
  • the tags as list of strings."
    (list
    (nth 4 (org-heading-components))
    (remove "" (s-split ":" (nth 5 (org-heading-components))))))

(defun org-tagged//row-for (heading item-tags tags)
"Create a row for a HEADING and its ITEM-TAGS for a table with TAGS."
(format "|%s|" (s-join "|" (-map (lambda (tag)
(if (-elem-index tag item-tags) heading "")) tags))))

(defun org-tagged/version ()
"Print org-tagge version."
(interactive)
(message "org-tagged 0.0.1"))

;;;###autoload
(defun org-dblock-write:tagged (params)
"Create a tagged dynamic block.
PARAMS must contain: :tags."
(insert
(let*
(
(tags (s-split "|" (plist-get params :tags)))
(table-title (plist-get params :tags))
(todos (org-map-entries 'org-tagged//map (plist-get params :match)))
(row-for (lambda (todo) (org-tagged//row-for (nth 0 todo) (nth 1 todo) tags)))
(table (s-join "\n" (-map row-for todos)))
)
(format "|%s|\n|--|\n%s" table-title table)))
(org-table-align))
(provide 'org-tagged)
#+end_src

Will try to do it as a melpa package this evening ...

commented

Hi

I am trying it at work. I miss some columnview characteristics, like column width. Some names are too long :/

Names could be shortened .. how does column view render long headings?

You can head over to the GitHub of org-tagged and open an issue there