How to show task's status, priority & deadlines in Table view mode

  • Displays references to journals with respect to graph’s setting Preferred date format.

Setup

  1. Go to config.edn (or global config.edn)
  2. Find :query/result-transforms setting
  3. Add new key :add-task-attrs with the code from the second message of this topic:
    :query/result-transforms {
      :add-task-attrs (fn [result]
        ...
      )
    
      ;; other result-transforms could be here
    }
    

Usage

  • Add line to any advanced query for tasks: :result-transform :add-task-attrs
  • Example for «Tasks for next 7 days» query:
    #+BEGIN_QUERY
    {:title ["Tasks for next 7 days"]
     :query [:find (pull ?block [*])
         :in $ ?start ?next
         :where
            (or
              [?block :block/scheduled ?d]
              [?block :block/deadline ?d])
            [(> ?d ?start)]
            [(< ?d ?next)]
            (task ?block #{"NOW", "LATER", "TODO", "DOING"})
     ]
     :inputs [:today :+7d]
     :result-transform :add-task-attrs
     :collapsed? false
    }
    #+END_QUERY
    

Restrictions

  • It uses english names for weekdays & months
  • It uses english suffixes for days: 1st, 2nd, …

Credits

Result transform code:

(fn [result]
    (def months {1 "January" 2 "February"  3 "March" 4 "April" 5 "May" 6 "June" 7 "July" 8 "August" 9 "September" 10 "October" 11 "November" 12 "December"})
    (def monthName (fn [dd]
          (get months (int dd))
         ))

    ;; source: https://discuss.logseq.com/t/add-query-input-or-function-day-of-week/18361/12
    (def days {0 "Saturday" 1 "Sunday" 2 "Monday" 3 "Tuesday" 4 "Wednesday" 5 "Thursday" 6 "Friday"})
    (def weekDay (fn [date]
          (def month (quot (mod date 10000) 100))
          (def month6 (quot (- month 8) 6))
          (def year6 (+ (quot date 10000) month6))
          (def yearnum (mod year6 100))
          (def century (quot year6 100))
          (def d (mod (+ (mod date 100) (quot (* 13 (inc (- month (* month6 12)))) 5) yearnum (quot   yearnum 4) 
          (quot century 4) (* 5 century)) 7))
          (get days d)
         ))

    (def suffixes {0 "th" 1 "st" 2 "nd" 3 "rd" 4 "th" 5 "th" 6 "th" 7 "th" 8 "th" 9 "th"})
    (def positionalSuffix (fn [dd]
          (if (or (= dd "11") (= dd "12") (= dd "13"))
            (get suffixes 0)
            (get suffixes (int (subs dd (count dd) 1))) )
         ))

    (def token (fn [s] (str "⟨" s "⟩")))
    (def format
      (-> (get (js->clj (call-api "get_user_configs")) "preferredDateFormat")
         (clojure.string/replace "do" (token "1"))
         (clojure.string/replace "dd" (token "2"))
         (clojure.string/replace "d" (token "3"))
         (clojure.string/replace "EEEE" (token "4"))
         (clojure.string/replace "EEE" (token "5"))
         (clojure.string/replace "EE" (token "6"))
         (clojure.string/replace "E" (token "7"))
         (clojure.string/replace "MMMM" (token "8"))
         (clojure.string/replace "MMM" (token "9"))
         (clojure.string/replace "MM" (token "10"))
         (clojure.string/replace "M" (token "11"))
         (clojure.string/replace "yyyy" (token "12"))
         (clojure.string/replace "yy" (token "13"))
      ))

    (def parseDate (fn [date]
          (if-not date nil
            (let [
                regex (re-pattern "(\\d{4})(\\d{2})(\\d{2})")
                [_ yyyy mm dd] (re-matches regex (str date))
                yy (subs yyyy 2 4)
                d (str (int dd))
                do (str d (positionalSuffix dd))
                mmmm (monthName mm)
                mmm (subs mmmm 0 3)
                m (str (int mm))
                eeee (weekDay date)
                eee (subs eeee 0 3)
                ee (subs eeee 0 2)
                e eee
              ]
              (-> format
                (clojure.string/replace (token "1") do)
                (clojure.string/replace (token "2") dd)
                (clojure.string/replace (token "3") d)
                (clojure.string/replace (token "4") eeee)
                (clojure.string/replace (token "5") eee)
                (clojure.string/replace (token "6") ee)
                (clojure.string/replace (token "7") e)
                (clojure.string/replace (token "8") mmmm)
                (clojure.string/replace (token "9") mmm)
                (clojure.string/replace (token "10") mm)
                (clojure.string/replace (token "11") m)
                (clojure.string/replace (token "12") yyyy)
                (clojure.string/replace (token "13") yy)
              )
            )
          )
         ))
    (def parseDateRef (fn [date]
          (if-not date nil
            (str "[[" (parseDate date) "]]")
          )
         ))


    (map (fn [x]
      (update x :block/properties (fn [u]
        (-> u
            (assoc :marker (str (get x :block/marker)) )
            (assoc :priority (str (get x :block/priority)) )
            (assoc :scheduled (parseDate (get x :block/scheduled)) )
            (assoc :scheduled-ref (parseDateRef (get x :block/scheduled)) )
            (assoc :deadline (parseDate (get x :block/deadline)) )
            (assoc :deadline-ref (parseDateRef (get x :block/deadline)) )
            (assoc :repeated? (str (get x :block/repeated?)) )
        )
      ))
    )
    result)
  )
4 Likes

With format set as :journal/page-title-format "EEEE, dd.MM.yyyy"
I get a bit of a weird result:

This goes a bit above my head to grasp and debug myself :sweat_smile:
But from the result I think that d gets parsed again to 7 in the day name.

Edit: yes actually. if I comment out the line (clojure.string/replace "d" d) the result is correct again. I think the replaces need to be in a proper order?

More edits :smiley:
Same problem occurs again with format that spells out the month… there’s an M in May and it leads to trouble:

Changing the order doesn’t solve this…
Format used here is do MMMM yyyy
So this may need to be adjusted for specific formats.

It should do 1 replace for each “type” based on which one it is. I dunno how to do so, but it should only try to replace M once.

1 Like

Ha-ha) this is funny bug)
Just removed the lines for «d» and «M» replacing. As quick fix: they doesn’t present in Logseq’s UI setting.

1 Like

Perfect. This has been amazing :smiley: totally replaced the result-transform of my queries with this beast in combination with a sort-by and conditional collapse (Result transform conditional)
I’m very happy now :heart_eyes:

I use :sort-tasks for those tasks that don’t use the conditional collapse… until I change all those queries to return ?has-child in the :find. lol!
And then :sort-tasks-collapsed for everything else.

Full config result-transforms:

 ;; Advanced queries `:result-transform` function.
 ;; Transform the query result before displaying it.
 :query/result-transforms
 {:sort-tasks (fn [result]
    (def months {1 "January" 2 "February"  3 "March" 4 "April" 5 "May" 6 "June" 7 "July" 8 "August" 9 "September" 10 "October" 11 "November" 12 "December"})
    (def monthName (fn [dd]
          (get months (int dd))
         ))

    ;; source: https://discuss.logseq.com/t/add-query-input-or-function-day-of-week/18361/12
    (def days {0 "Saturday" 1 "Sunday" 2 "Monday" 3 "Tuesday" 4 "Wednesday" 5 "Thursday" 6 "Friday"})
    (def weekDay (fn [date]
          (def month (quot (mod date 10000) 100))
          (def month6 (quot (- month 8) 6))
          (def year6 (+ (quot date 10000) month6))
          (def yearnum (mod year6 100))
          (def century (quot year6 100))
          (def d (mod (+ (mod date 100) (quot (* 13 (inc (- month (* month6 12)))) 5) yearnum (quot   yearnum 4) 
          (quot century 4) (* 5 century)) 7))
          (get days d)
         ))

    (def suffixes {0 "th" 1 "st" 2 "nd" 3 "rd" 4 "th" 5 "th" 6 "th" 7 "th" 8 "th" 9 "th"})
    (def positionalSuffix (fn [dd]
          (if (or (= dd "11") (= dd "12") (= dd "13"))
            (get suffixes 0)
            (get suffixes (int (subs dd (count dd) 1))) )
         ))

    (def token (fn [s] (str "⟨" s "⟩")))
    (def format
      (-> (get (js->clj (call-api "get_user_configs")) "preferredDateFormat")
         (clojure.string/replace "do" (token "1"))
         (clojure.string/replace "dd" (token "2"))
         (clojure.string/replace "d" (token "3"))
         (clojure.string/replace "EEEE" (token "4"))
         (clojure.string/replace "EEE" (token "5"))
         (clojure.string/replace "EE" (token "6"))
         (clojure.string/replace "E" (token "7"))
         (clojure.string/replace "MMMM" (token "8"))
         (clojure.string/replace "MMM" (token "9"))
         (clojure.string/replace "MM" (token "10"))
         (clojure.string/replace "M" (token "11"))
         (clojure.string/replace "yyyy" (token "12"))
         (clojure.string/replace "yy" (token "13"))
      ))

    (def parseDate (fn [date]
          (if-not date nil
            (let [
                regex (re-pattern "(\\d{4})(\\d{2})(\\d{2})")
                [_ yyyy mm dd] (re-matches regex (str date))
                yy (subs yyyy 2 4)
                d (str (int dd))
                do (str d (positionalSuffix dd))
                mmmm (monthName mm)
                mmm (subs mmmm 0 3)
                m (str (int mm))
                eeee (weekDay date)
                eee (subs eeee 0 3)
                ee (subs eeee 0 2)
                e eee
              ]
              (-> format
                (clojure.string/replace (token "1") do)
                (clojure.string/replace (token "2") dd)
                (clojure.string/replace (token "3") d)
                (clojure.string/replace (token "4") eeee)
                (clojure.string/replace (token "5") eee)
                (clojure.string/replace (token "6") ee)
                (clojure.string/replace (token "7") e)
                (clojure.string/replace (token "8") mmmm)
                (clojure.string/replace (token "9") mmm)
                (clojure.string/replace (token "10") mm)
                (clojure.string/replace (token "11") m)
                (clojure.string/replace (token "12") yyyy)
                (clojure.string/replace (token "13") yy)
              )
            )
          )
         ))
    (def parseDateRef (fn [date]
          (if-not date nil
            (str "[[" (parseDate date) "]]")
          )
         ))

    (sort-by 
      (juxt 
        (fn [r] (get r :block/priority "W"))
        (fn [r] (get r :block/scheduled 99999999))
        (fn [r] (get r :block/deadline 99999999))
        (fn [r] (get r :block/content))
      )
    (map (fn [x]
      (update x :block/properties (fn [u]
        (-> u
            (assoc :marker (str (get x :block/marker)) )
            (assoc :priority (str (get x :block/priority)) )
            (assoc :scheduled (parseDate (get x :block/scheduled)) )
            (assoc :scheduled-ref (parseDateRef (get x :block/scheduled)) )
            (assoc :deadline (parseDate (get x :block/deadline)) )
            (assoc :deadline-ref (parseDateRef (get x :block/deadline)) )
            (assoc :repeated? (str (get x :block/repeated?)) )
        )
      ))
    )
    result) )
  )
  :sort-tasks-collapsed (fn [result]
    (def months {1 "January" 2 "February"  3 "March" 4 "April" 5 "May" 6 "June" 7 "July" 8 "August" 9 "September" 10 "October" 11 "November" 12 "December"})
    (def monthName (fn [dd]
          (get months (int dd))
         ))

    ;; source: https://discuss.logseq.com/t/add-query-input-or-function-day-of-week/18361/12
    (def days {0 "Saturday" 1 "Sunday" 2 "Monday" 3 "Tuesday" 4 "Wednesday" 5 "Thursday" 6 "Friday"})
    (def weekDay (fn [date]
          (def month (quot (mod date 10000) 100))
          (def month6 (quot (- month 8) 6))
          (def year6 (+ (quot date 10000) month6))
          (def yearnum (mod year6 100))
          (def century (quot year6 100))
          (def d (mod (+ (mod date 100) (quot (* 13 (inc (- month (* month6 12)))) 5) yearnum (quot   yearnum 4) 
          (quot century 4) (* 5 century)) 7))
          (get days d)
         ))

    (def suffixes {0 "th" 1 "st" 2 "nd" 3 "rd" 4 "th" 5 "th" 6 "th" 7 "th" 8 "th" 9 "th"})
    (def positionalSuffix (fn [dd]
          (if (or (= dd "11") (= dd "12") (= dd "13"))
            (get suffixes 0)
            (get suffixes (int (subs dd (count dd) 1))) )
         ))

    (def token (fn [s] (str "⟨" s "⟩")))
    (def format
      (-> (get (js->clj (call-api "get_user_configs")) "preferredDateFormat")
         (clojure.string/replace "do" (token "1"))
         (clojure.string/replace "dd" (token "2"))
         (clojure.string/replace "d" (token "3"))
         (clojure.string/replace "EEEE" (token "4"))
         (clojure.string/replace "EEE" (token "5"))
         (clojure.string/replace "EE" (token "6"))
         (clojure.string/replace "E" (token "7"))
         (clojure.string/replace "MMMM" (token "8"))
         (clojure.string/replace "MMM" (token "9"))
         (clojure.string/replace "MM" (token "10"))
         (clojure.string/replace "M" (token "11"))
         (clojure.string/replace "yyyy" (token "12"))
         (clojure.string/replace "yy" (token "13"))
      ))

    (def parseDate (fn [date]
          (if-not date nil
            (let [
                regex (re-pattern "(\\d{4})(\\d{2})(\\d{2})")
                [_ yyyy mm dd] (re-matches regex (str date))
                yy (subs yyyy 2 4)
                d (str (int dd))
                do (str d (positionalSuffix dd))
                mmmm (monthName mm)
                mmm (subs mmmm 0 3)
                m (str (int mm))
                eeee (weekDay date)
                eee (subs eeee 0 3)
                ee (subs eeee 0 2)
                e eee
              ]
              (-> format
                (clojure.string/replace (token "1") do)
                (clojure.string/replace (token "2") dd)
                (clojure.string/replace (token "3") d)
                (clojure.string/replace (token "4") eeee)
                (clojure.string/replace (token "5") eee)
                (clojure.string/replace (token "6") ee)
                (clojure.string/replace (token "7") e)
                (clojure.string/replace (token "8") mmmm)
                (clojure.string/replace (token "9") mmm)
                (clojure.string/replace (token "10") mm)
                (clojure.string/replace (token "11") m)
                (clojure.string/replace (token "12") yyyy)
                (clojure.string/replace (token "13") yy)
              )
            )
          )
         ))
    (def parseDateRef (fn [date]
          (if-not date nil
            (str "[[" (parseDate date) "]]")
          )
         ))

    (sort-by 
      (juxt 
        (fn [r] (get r :block/priority "W"))
        (fn [r] (get r :block/scheduled 99999999))
        (fn [r] (get r :block/deadline 99999999))
        (fn [r] (get r :block/content))
      )
    (map (fn [x]
      (update x :block/properties (fn [u]
        (-> u
            (assoc :marker (str (get x :block/marker)) )
            (assoc :priority (str (get x :block/priority)) )
            (assoc :scheduled (parseDate (get x :block/scheduled)) )
            (assoc :scheduled-ref (parseDateRef (get x :block/scheduled)) )
            (assoc :deadline (parseDate (get x :block/deadline)) )
            (assoc :deadline-ref (parseDateRef (get x :block/deadline)) )
            (assoc :repeated? (str (get x :block/repeated?)) )
        )
      ))
    )
    (for [[collapsed, b] (partition 2 result)]
      (assoc b :block/collapsed? collapsed)
    )
    ) )
  )
 }

Ps. yes I realize one acts on tables and another on lists… but I toggle between the two views a lot I’ve noticed :slight_smile: so it is nice to not have to change the query lol.

Edit: updated according to bugfixes :point_down:t4:

3 Likes

Just made long fix:

  • return «d», «M» placeholders
  • add «yy» placeholder
  • some refactoring for better perfomance

Checked on both your patterns:

  • do MMMM yyyy
  • EEEE, dd.MM.yyyy
3 Likes

This is beautifully useful. Thank you for sharing it.

1 Like

Hi @stdword
This works great as advanced query, thank you :slightly_smiling_face:

I am however wondering what your workflow for this is - do you typically insert this into every daily journal or just do some kind of one-off review each week?

I was thinking of making this a permanent fixture on the bottom of each Journal.
Via config.edn, I disabled the default scheduled and deadline query

:feature/disable-scheduled-and-deadline-query? true

And then attempted to add this into default queries

 :default-queries
 {:journals
  [{:title ["Tasks for next 7 days"]
 :query [:find (pull ?block [*])
     :in $ ?start ?next
     :where
        (or
          [?block :block/scheduled ?d]
          [?block :block/deadline ?d])
        [(> ?d ?start)]
        [(< ?d ?next)]
        (task ?block #{"NOW", "LATER", "TODO", "DOING"})
 ]
 :inputs [:today :+7d]
 :result-transform :add-task-attrs
 :collapsed? false
}]
 }

But it seems that if and only if the query is in default-queries - it becomes impossible to view table mode. I don’t suppose you know of a way to default the query to table mode?

Cheers

1 Like

You could use :table-view? true to default to table mode.

This works great as advanced query, thank you :slightly_smiling_face:

:pray::heart:

what your workflow for this is?

My workflow is simple: I don’t use this query for myself (because I don’t use Logseq for tasks management), it was just interesting clojure task.

I don’t suppose you know of a way to default the query to table mode?

I only aware of :table-view? true setting, as @etc mentioned.

Hi @etc

Please can you confirm my usage of this is correct?

This seems to cause all the results to be hidden/invisible. I wonder if this is a limitation of default queries, specifically?
image

Cheers

1 Like

Yes. Default queries don’t support table view.
Could be a feature request if something like that doesn’t already exists.

2 Likes

I tested it too and get a similar result. Both @siferiax an you are right it seems, and the feature is unfinished for default queries.

1 Like

@Siferiax, @etc; thank you both for confirmation.

I have raised a feature request for this.

Cheers.

2 Likes