Use org-radiobutton to select an option from a list
Date | Change |
---|---|
2021-05-24 | Since org-mode 9.4.0 there is a built-in org-list-checkbox-radio-mode . It works very similar to this package so make sure to check it out and possibly migrate your org files. |
Ever since I've come across the Literate DevOps article I was hooked and immediately started writing down "org notebooks" every time an incident occured along with all the code and steps on how to fix it in case it might happen in the future (protip: it will happen again).
Recently we had some problems with webhook requests behaving weird and
so I created a little notebook to query the mongo database where we
store all the requests and some more functions (ranging from elisp to
jq to ruby) to process the results. As you sure know, threading data
between code blocks in different languages is painless with org-mode
and babel.
So imagine a block like this (using ob-mongo):
#+NAME: query #+BEGIN_SRC mongo :db logs :host localhost :port 27017 db.webhookLogs.find({endpoint: "AddCustomer"}).sort({_id: -1}).limit(1) #+END_SRC
This gives me the most recent request to the AddCustomer
endpoint.
The results of this block are then piped into other code blocks to
process the request, you can imagine how that looks.
Usually I run the entire app stack locally but we also have separate staging and production environments. So after I run the notebook on my own local stack I want to try it out in staging.
I use prodigy to manage my ssh tunnels and so all I need to do is
change the port to one pointing to staging and re-run the notebook.
The problem is that I have multiple query blocks and so I have to go
and change all of the :port
arguments.
I have solved this by creating a block that would work as a source for the port and then reference it dynamically in the header line:
#+NAME: port #+BEGIN_SRC elisp 27017 #+END_SRC #+NAME: query #+BEGIN_SRC mongo :db logs :host localhost :port (org-babel-ref-resolve "port") db.webhookLogs.find({endpoint: "AddCustomer"}).sort({_id: -1}).limit(1) #+END_SRC
Since we can call elisp in the header I use org-babel-ref-resolve
and
give it the name of the source block and babel will automatically
replace it with the value of the block.
This solves the problem of changing the constant at one place but as I got to work with more environments I tended to forget what port was what. So I created a list above the block to remind me of the available values:
Use one of the following ports to operate on the given environment: - localhost :: 27017 - staging :: 27004 - production :: 27005 #+NAME: port #+BEGIN_SRC elisp 27017 #+END_SRC #+NAME: query #+BEGIN_SRC mongo :db logs :host localhost :port (org-babel-ref-resolve "port") db.webhookLogs.find({endpoint: "AddCustomer"}).sort({_id: -1}).limit(1) #+END_SRC
We can use the org mode list description syntax foo ::
to attach a
label to each item and leave the number as the "value".
This is starting to look an awful lot like a list of choices I could pick from. So my thinking goes like this: let's make it a checkbox list and then select the option by checking the option. The trouble there is that toggling the input would require me to un-toggle the current one and then toggle the desired option. Ideally, toggling one checkbox would uncheck the other so that there is always exactly one option selected: in other words, I wanted a radiobutton list.
After a quick google session I've found (via Irreal) that John Kitchin already figured this out. I took his code and cleaned it up a bit to work with "modern" org mode (the post is three years old) and packaged it as org-radiobutton.
Now I have a nice menu I can go to and with a single C-c C-c
on the
option I want I can select the environment where to run the notebook.
Org mode is so cool!
Check one of the following ports to operate on the given environment: #+attr_org: :radio #+NAME: port - [ ] localhost :: 27017 - [X] staging :: 27004 - [ ] production :: 27005 #+NAME: query #+BEGIN_SRC mongo :db logs :host localhost :port (org-radiobutton-value "port") db.webhookLogs.find({endpoint: "AddCustomer"}).sort({_id: -1}).limit(1) #+END_SRC
I'm going over all of my notebooks converting all the ugly option hacks to this setup and it is so damn pleasing! :D