Files
obsidian-workflow-template/_Sources/2023-07-31/Grouping - Tasks User Guide - Obsidian Publish.md
Mathis Gauthey f366d5b7b6 Initial commit
2023-08-05 19:14:53 +01:00

26 KiB

id, title, tags, state, date_saved, date_read, date_archived
id title tags state date_saved date_read date_archived
id-generated-by-omnivore Grouping - Tasks User Guide - Obsidian Publish
obsidian-tasks
ARCHIVED 2023-07-16 10:23:40 2023-07-16 12:18:14 2023-07-16T10:05:16.592Z

Grouping - Tasks User Guide - Obsidian Publish

#Omnivore

Read on Omnivore Read Original

Webpage

Grouping

Contents

This page is long. Here are some links to the main sections:

Basics

Introduced in Tasks 1.6.0.

By default, Tasks displays tasks in a single list.

To divide the matching tasks up with headings, you can add group by lines to the query.

Custom Groups

group by function was introduced in Tasks 4.0.0.

Tasks provides many built-in grouping options, but sometimes they don't quite do what is wanted by all users.

Now Tasks has a powerful mechanism for you to create your own custom groups, offering incredible flexibility.

There are many examples of the custom grouping instruction group by function in the documentation below, with explanations, for when the group by instructions built in to Tasks do not satisfy your preferences.

You can find out more about this very powerful facility in Custom Grouping.

Group by Task Statuses

For more information, including adding your own customised statuses, see Statuses.

Status

  • group by status (Done or Todo, which is capitalized for visibility in the headings)
    • Note that the Done group is displayed before the Todo group, which differs from the Sorting ordering of this property.
      * Done is used for tasks status types DONE, CANCELLED and NON_TASK
      * Todo is used for status types with type TODO and IN_PROGRESS

Since Tasks 4.0.0, custom grouping by status is now possible.

  • group by function task.isDone ? "Action Required" : "Nothing To Do"
    • Use JavaScript's ternary operator to choose what to do for true (after the ?) and false (after the :) values.

Status Name

  • group by status.name
    • This groups by the names you give to your custom statuses, in alphabetical order.

group by status.name was introduced in Tasks 1.23.0.

Since Tasks 4.0.0, custom grouping by status names is now possible.

  • group by function task.status.name
    • Identical to "group by status.name".
  • group by function task.status.name.toUpperCase()
    • Convert the status names to capitals.

Status Type

  • group by status.type
    • This groups by the types you have given to your custom statuses.
    • The groups will appear in this order, and with these group names:
      * IN_PROGRESS
      * TODO
      * DONE
      * CANCELLED
      * NON_TASK

group by status.type was introduced in Tasks 1.23.0.

Since Tasks 4.0.0, custom grouping by status types is now possible.

  • group by function task.status.type
    • Unlike "group by status.type", this sorts the status types in alphabetical order.

Status Symbol

There is no built-in instruction to group by status symbols.

Since Tasks 4.0.0, custom grouping by status symbol is now possible.

  • group by function "Status symbol: " + task.status.symbol.replace(" ", "space")
    • Group by the status symbol, making space characters visible.

Next Status Symbol

There is no built-in instruction to group by next status symbols.

Since Tasks 4.0.0, custom grouping by next status symbol is now possible.

  • group by function "Next status symbol: " + task.status.nextSymbol.replace(" ", "space")
    • Group by the next status symbol, making space characters visible.

Group by Dates in Tasks

Due Date

  • group by due

    • The due date of the task, including the week-day, or No due date.
  • due grouping option was introduced in Tasks 1.7.0.

Since Tasks 4.0.0, custom grouping by due date is now possible.

These examples all use task.due property, which is a TasksDate object. You can see the current TasksDate source code, to explore its capabilities.

  • group by function task.due.format("YYYY-MM-DD dddd")
    • Like "group by due", except it uses no heading, instead of a heading "No due date", if there is no due date.
  • group by function task.due.formatAsDate()
    • Format date as YYYY-MM-DD or empty string (so no heading) if there is no due date.
  • group by function task.due.formatAsDateAndTime()
    • Format date as YYYY-MM-DD HH:mm or empty string if no due date.
    • Note:
      * This is shown for demonstration purposes.
      * Currently the Tasks plugin does not support storing of times.
      * Do not add times to your tasks, as it will break the reading of task data.
  • group by function task.due.format("YYYY[%%]-MM[%%] MMM", "no due date")
    • Group by month, for example 2023%%-05%% May ...
      * ... which gets rendered by Obsidian as 2023 May.
    • Or show a default heading "no due date" if no date.
    • The hidden month number is added, commented-out between two %% strings, to control the sort order of headings.
    • To escape characters in format strings, you can wrap the characters in square brackets (here, [%%]).
  • group by function task.due.format("YYYY[%%]-MM[%%] MMM [- Week] WW")
    • Group by month and week number, for example 2023%%-05%% May - Week 22 ...
      * ... which gets rendered by Obsidian as 2023 May - Week 22.
    • If the month number is not embedded, in some years the first or last week of the year is displayed in a non-logical order.

DON'T PANIC! For users who are comfortable with JavaScript, these more complicated examples may also be of interest:

  • group by function task.due.moment?.fromNow() || ""
    • Group by the time from now, for example "8 days ago".
    • Because Moment.fromNow() is not provided by TasksDate, we need special code for when there is no date value.
    • Whilst interesting, the alphabetical sort order makes the headings a little hard to read.
  • group by function task.due.format("dddd")
    • Group by day of the week (Monday, Tuesday, etc).
    • The day names are sorted alphabetically.
  • group by function task.due.format("[%%]d[%%]dddd")
    • Group by day of the week (Sunday, Monday, Tuesday, etc).
    • The day names are sorted in date order, starting with Sunday.
  • group by function task.due.moment ? ( task.due.moment.day() === 0 ? task.due.format("[%%][8][%%]dddd") : task.due.format("[%%]d[%%]dddd") ) : "Undated"
    • Group by day of the week (Monday, Tuesday, etc).
    • The day names are sorted in date order, starting with Monday.
    • Tasks without due dates are displayed at the end, under a heading "Undated".
    • This is best understood by pasting it in to a Tasks block in Obsidian and then deleting parts of the expression.
    • The key technique is to say that if the day is Sunday (0), then force it to be displayed as date number 8, so it comes after the other days of the week.
  • group by function (!task.due.moment) ? '%%4%% Undated' : result = task.due.moment.isBefore(moment(), 'day') ? '%%1%% Overdue' : result = task.due.moment.isSame(moment(), 'day') ? '%%2%% Today' : '%%3%% Future'
    • Group task due dates in to 4 broad categories: Overdue, Today, Future and Undated, displayed in that order.
    • Try this on a line before group by due if there are a lot of due date headings, and you would like them to be broken down in to some kind of structure.
    • A limitation of Tasks expressions is that they each need to fit on a single line, so this uses nested ternary operators, making it powerful but very hard to read.
    • In fact, for ease of development and testing, it was written in a full-fledged development environment as a series of if/else blocks, and then automatically refactored in these nested ternary operators.
  • group by function (!task.due.moment) ? '%%4%% ==Undated==' : result = task.due.moment.isBefore(moment(), 'day') ? '%%1%% ==Overdue==' : result = task.due.moment.isSame(moment(), 'day') ? '%%2%% ==Today==' : '%%3%% ==Future=='
    • As above, but the headings Overdue, Today, Future and Undated are highlighted.
    • See the sample screenshot below.

Tasks grouped by due date category, and then by due date

Sample image showing tasks grouped first by highlighted words Overdue, Today, Future and Undated, and then by individual due date.

Done Date

  • group by done

    • The done date of the task, including the week-day, or No done date.
  • done grouping option was introduced in Tasks 1.7.0.

Since Tasks 4.0.0, custom grouping by done date is now possible.

  • group by function task.done.format("YYYY-MM-DD dddd")
    • Like "group by done", except it uses an empty string instead of "No done date" if there is no done date.

Scheduled Date

  • group by scheduled

    • The scheduled date of the task, including the week-day, or No scheduled date.
  • scheduled grouping option was introduced in Tasks 1.7.0.

Since Tasks 4.0.0, custom grouping by scheduled date is now possible.

  • group by function task.scheduled.format("YYYY-MM-DD dddd")
    • Like "group by scheduled", except it uses an empty string instead of "No scheduled date" if there is no scheduled date.

Start Date

  • group by start

    • The start date of the task, including the week-day, or No start date.
  • start grouping option was introduced in Tasks 1.7.0.

Since Tasks 4.0.0, custom grouping by start date is now possible.

  • group by function task.start.format("YYYY-MM-DD dddd")

    • Like "group by start", except it uses an empty string instead of "No start date" if there is no start date.
  • group by created

    • The created date of the task, including the week-day, or No created date.

created grouping option was introduced in Tasks 2.0.0.

Since Tasks 4.0.0, custom grouping by created date is now possible.

  • group by function task.created.format("YYYY-MM-DD dddd")
    • Like "group by created", except it uses an empty string instead of "No created date" if there is no created date.

Happens

  • group by happens
    • The earliest of start date, scheduled date, and due date, including the week-day, or No happens date if none of those are set.

happens grouping option was introduced in Tasks 1.11.0.

Since Tasks 4.0.0, custom grouping by happens date is now possible.

  • group by function task.happens.format("YYYY-MM-DD dddd")
    • Like "group by happens", except it uses an empty string instead of "No happens date" if there is no happens date.

Group by Other Task Properties

As well as the date-related groups above, groups can be created from properties in individual tasks.

Description

There is no built-in instruction to group by description.

Since Tasks 4.0.0, custom grouping by description is now possible.

  • group by function task.description
    • group by description.
    • This might be useful for finding completed recurrences of the same task.
  • group by function task.description.toUpperCase()
    • Convert the description to capitals.
  • group by function task.description.slice(0, 25)
    • Truncate descriptions to at most their first 25 characters, and group by that string.
  • group by function task.description.replace('short', '==short==')
    • Highlight the word "short" in any group descriptions.

Description without tags

Since Tasks 4.2.0, it is possible to remove tags from the descriptions in custom groups, for use in custom grouping.

The value task.descriptionWithoutTags returns a copy of the description with all the tags removed, so that you can group together any tasks whose descriptions differ only by their tags.

  • group by function task.descriptionWithoutTags
    • Like group by description, but it removes any tags from the group headings.
    • This might be useful for finding completed recurrences of the same task, even if the tags differ in some recurrences.

Priority

  • group by priority

    • The priority of the task, namely one of:
      * Highest priority
      * High priority
      * Medium priority
      * Normal priority
      * Low priority
      * Lowest priority
  • priority grouping option was introduced in Tasks 1.11.0.

Since Tasks 4.0.0, custom grouping by priority name and number is now possible.

Using the priority name:

  • group by function task.priorityName
    • Group by the task's priority name.
    • The priority names are displayed in alphabetical order.
    • Note that the default priority is called 'Normal', as opposed to with group by priority which calls the default 'None'.
  • group by function '%%' + task.priorityNumber.toString() + '%%' + task.priorityName +' priority'
    • Group by the task's priority name.
    • The hidden priority number ensures that the headings are written from highest to lowest priority.
    • Note that the default priority is called 'Normal', as opposed to with group by priority which calls the default 'None'.

Using the priority number:

  • group by function task.priorityNumber
    • Group by the task's priority number, where Highest is 0 and Lowest is 5.

Urgency

  • group by urgency (urgency)

    • The groups run from the highest urgency to the lowest.
    • You can reverse this with group by urgency reverse.
  • urgency grouping option was introduced in Tasks 3.6.0.

  • In Tasks 4.0.0 the order of group by urgency was reversed, to put most urgent tasks first. Add or remove the word reverse to get the original order.

Since Tasks 4.0.0, custom grouping by urgency is now possible.

  • group by function task.urgency.toFixed(3)
    • Show the urgency to 3 decimal places, unlike the built-in "group by urgency" which uses 2.

Recurrence

  • group by recurring

    • Whether the task is recurring: either Recurring or Not Recurring.
  • group by recurrence

    • The recurrence rule of the task, for example every week on Sunday, or None for non-recurring tasks.
    • Note that the text displayed is generated programmatically and standardised, and so may not exactly match the text in any manually typed tasks. For example, a task with 🔁 every Sunday is grouped in every week on Sunday.
  • recurring and recurrence grouping options were introduced in Tasks 1.11.0.

Since Tasks 4.0.0, custom grouping by recurrence is now possible.

  • group by function task.isRecurring ? "Recurring" : "Non-Recurring"

    • Use JavaScript's ternary operator to choose what to do for true (after the ?) and false (after the :) values.
  • group by function task.recurrenceRule.replace('when done', '==when done==')

    • Group by recurrence rule, highlighting any occurrences of the words "when done".

Tags

  • group by tags

    • The tags of the tasks or (No tags). If the task has multiple tags, it will show up under every tag.
  • tags grouping option was introduced in Tasks 1.10.0.

  • group by function task.tags

    • Like "group by tags" except that tasks with no tags have no heading instead of "(No tags)".
  • group by function task.tags.join(", ")

    • Tasks with multiple tags are listed once, with a heading that combines all the tags.
    • Separating with commas means the tags are clickable in the headings.
  • group by function task.tags.sort().join(", ")

    • As above, but sorting the tags first ensures that the final headings are independent of order of tags in the tasks.
  • group by function task.tags.filter( (tag) => tag.includes("#context/") )

    • Only create headings for tags that contain "#context/".
  • group by function task.tags.filter( (tag) => ! tag.includes("#tag") )

    • Create headings for all tags that do not contain "#tag".

These are more complicated examples, which you might like to copy if you use tasks with nested tags and wish to group them at different tag nesting levels.

  • group by function task.tags.map( (tag) => tag.split('/')[0].replace('#', '') )
    • #tag/subtag/sub-sub-tag gives tag.
  • group by function task.tags.map( (tag) => tag.split('/')[1] ? tag.split('/').slice(1, 2) : '')
    • #tag/subtag/sub-sub-tag gives subtag.
  • group by function task.tags.map( (tag) => tag.split('/')[2] ? tag.split('/').slice(2, 3) : '')
    • #tag/subtag/sub-sub-tag gives sub-sub-tag.
  • group by function task.tags.map( (tag) => tag.split('/')[3] ? tag.split('/').slice(3, 4) : '')
    • #tag/subtag/sub-sub-tag gives no heading, as there is no value at the 4th level.
  • group by function task.tags.map( (tag) => tag.split('/')[0] )
    • #tag/subtag/sub-sub-tag gives #tag.
  • group by function task.tags.map( (tag) => tag.split('/')[1] ? tag.split('/').slice(0, 2).join('/') : '')
    • #tag/subtag/sub-sub-tag gives #tag/subtag.
  • group by function task.tags.map( (tag) => tag.split('/')[2] ? tag.split('/').slice(0, 3).join('/') : '')
    • #tag/subtag/sub-sub-tag gives #tag/subtag/sub-sub-tag.
  • group by function task.tags.map( (tag) => tag.split('/')[3] ? tag.split('/').slice(0, 4).join('/') : '')
    • #tag/subtag/sub-sub-tag gives no heading, as there is no value at the 4th level.

Original Markdown

There is no built-in instruction to group by the original markdown line.

Since Tasks 4.0.0, custom grouping by original markdown line is now possible.

For example, this could be used to extract information from task.originalMarkdown that Tasks does not parse, to use for grouping tasks.

  • group by function '``' + task.originalMarkdown + '``'
    • Group by the raw text of the task's original line in the MarkDown file as code.
    • Note the pairs of backtick characters ('`'), to preserve even single backtick characters in the task line.
    • It's important to prevent the task checkbox (for example, '[ ]') from being rendered in the heading, as it gets very confusing if there are checkboxes on both headings and tasks.
  • group by function task.originalMarkdown.replace(/^[^\[\]]+\[.\] */, '')
    • An alternative to formatting the markdown line as code is to remove everything up to the end of the checkbox.
    • Then render the rest of the task line as normal markdown.

Group by File Properties

File Path

  • group by path (the path to the file that contains the task, that is, the folder and the filename)

Since Tasks 4.0.0, custom grouping by file path is now possible.

  • group by function task.file.path
    • Like 'group by path' but includes the file extension.

Root

  • group by root (the top-level folder of the file that contains the task, that is, the first directory in the path, which will be / for files in root of the vault)

root grouping option was introduced in Tasks 1.11.0.

Since Tasks 4.0.0, custom grouping by root folder is now possible.

  • group by function task.file.root
    • Same as 'group by root'.

Folder

  • group by folder (the folder to the file that contains the task, which always ends in / and will be exactly / for files in root of the vault)

Since Tasks 4.0.0, custom grouping by folder is now possible.

  • group by function task.file.folder
    • Same as 'group by folder'.
  • group by function task.file.folder.slice(0, -1).split('/').pop() + '/'
    • Group by the immediate parent folder of the file containing task.
    • Here's how it works:
      * '.slice(0, -1)' removes the trailing slash ('/') from the original folder.
      * '.split('/')' divides the remaining path up in to an array of folder names.
      * '.pop()' returns the last folder name, that is, the parent of the file containing the task.
      * Then the trailing slash is added back, to ensure we do not get an empty string for files in the top level of the vault.

File Name

  • group by filename (the link to the file that contains the task, without the .md extension)
    • Note that tasks from different notes with the same file name will be grouped together in the same group.

Since Tasks 4.0.0, custom grouping by file name is now possible.

  • group by function task.file.filename
    • Like 'group by filename' but does not link to the file.
  • group by function '[[' + task.file.filename.replace('.md', '') + ( task.hasHeading ? ('#' + task.heading) : '') + ']]'
    • Like 'group by backlink' but links to the heading in the file.
  • group by backlink (the text that would be shown in the task's backlink, combining the task's file name and heading, but with no link added)

Heading

  • group by heading (the heading preceding the task, or (No heading) if there are no headings in the file)

Since Tasks 4.0.0, custom grouping by heading is now possible.

  • group by function (task.heading + '.md' === task.file.filename) ? '' : task.heading
    • Group by heading, but only if the heading differs from the file name.
    • This works well immediately after a 'group by filename' line.
    • Note the three equals signs '===': these are important for safety in JavaScript.

Multiple groups

You can add multiple group by query options, each on an extra line. This will create nested groups. The first group has the highest priority.

Each subsequent group by will generate a new heading-level within the existing grouping:

  • First group by is displayed as h4 headings
  • Second group by is displayed as h5 headings
  • Third and subsequent group by are displayed as h6 headings

Headings are displayed in case-sensitive alphabetical order, not the original order.

Refining groups

Reversing groups

Reversing of group headings was introduced in Tasks 3.7.0.

After the name of the property that you want to group by, you can add the reverse keyword. If given, the group headings will be reversed for that property.

For example:

  • group by due will sort the group headings:
    • from oldest due date first...
    • to newest due date last
  • group by due reverse will sort the group headings:
    • from newest due date first...
    • to oldest due date last

The reverse keyword controls the order that group headings are displayed.

The sort by facility, by contrast, controls the order in which displays are displayed inside each group.

Limiting group size

You can limit the number of tasks in each group, perhaps to work on the most important things first.

Notes

The order of operations ensures that grouping does not modify which tasks are displayed, for example when the limit options are used:

  1. all the filter instructions are run
  2. then any sorting instructions are run
  3. then any limit instructions are run
  4. then any grouping instructions are run
  5. then any limit groups instructions are run

Screenshots

Before

Here is an example Tasks result, without any group by commands:

Tasks Ungrouped

Tasks not grouped.

After

And here is what this might look like, when grouped by folder, filename and heading:

Tasks Grouped

Tasks grouped.

Examples

Give me three levels of grouping, to indicate the locations of my tasks:

```tasks
not done
group by folder
group by filename
group by heading

Show me tasks I need to do today - and put today's tasks first, for visibility:

```routeros
```tasks
not done
due before tomorrow
group by due reverse

Grouping