OmniFocus: Task Status Board
Here’s an example shortcut that demonstrates the powerful interaction between Omni Automation and Shortcuts: using the best of both technologies to deliver solutions greater than either could deliver on their own.
This shortcut will create and display, alongside the current OmniFocus window, an HTML-based page showing a 3-column task review based upon the use of three specified tags.
IMPORTANT: On iOS and iPadOS most browsers are blocked from opening HTML files. The iCab Mobile (Web Browser) application by Alexander Clauss appears to be an exception, and displays the shortcut-generated task status table HTML file. On iOS/iPadOS you will need to adjust the last two actions in the shortcut to use this application.
Video 1: Task Status Board |
Shortcut creates and displays, alongside the current OmniFocus window, an HTML-based page showing a 3-column task review based upon the use of three specified tags. |
|
Processing Omni Automation Script
Here is the script that generates the custom content, wrapped within the HTML opening and closing content.
Generate HTML Status Page
(async () => {
try {
tag1Title = argument.input.tagTitle1
tag2Title = argument.input.tagTitle2
tag3Title = argument.input.tagTitle3
tag1 = flattenedTags.byName(tag1Title) || new Tag(tag1Title)
tag2 = flattenedTags.byName(tag2Title) || new Tag(tag2Title)
tag3 = flattenedTags.byName(tag3Title) || new Tag(tag3Title)
items1 = tag1.tasks.filter(task => {
return task.taskStatus === Task.Status.Available
})
items2 = tag2.tasks.filter(task => {
return task.taskStatus === Task.Status.Available
})
items3 = tag3.tasks.filter(task => {
return task.taskStatus === Task.Status.Available
})
lengths = [items1.length, items2.length, items3.length]
if(lengths === [0, 0, 0]){
throw {
name:"No Matches",
message:`No tasks have been tagged with: ${tag3Title}, ${tag2Title}, or ${tag3Title}`
}
}
loopCount = Math.max.apply(null, lengths)
row = "\t\t
\nXXXX\n\t\t "cell = "\t\t\t
XXXX "
rows = []
for (index = 0; index < loopCount; index++) {
item = items1[index]
if (typeof item === "undefined"){cell1 = "
"} else { title = item.name
link = `omnifocus://task/${item.id.primaryKey}`
// cell1 = cell.replace("XXXX",`<a href="${link}">${title}</a>`)
cell1 = "<td>" + `<a href="${link}">${title}</a>` + "</td>"
}
item = items2[index]
if (typeof item === "undefined"){cell2 = "
"} else { title = item.name
link = `omnifocus://task/${item.id.primaryKey}`
// cell2 = cell.replace("XXXX",`<a href="${link}">${title}</a>`)
cell2 = "<td>" + `<a href="${link}">${title}</a>` + "</td>"
}
item = items3[index]
if (typeof item === "undefined"){cell3 = "
"} else { title = item.name
link = `omnifocus://task/${item.id.primaryKey}`
// cell3 = cell.replace("XXXX",`<a href="${link}">${title}</a>`)
cell3 = "<td>" + `<a href="${link}">${title}</a>` + "</td>"
}
rowContent = "\t\t\t" + cell1 + "\n" +
"\t\t\t" + cell2 + "\n" +
"\t\t\t" + cell3
rowContent = row.replace("XXXX", rowContent)
rows.push(rowContent)
}
return (argument.input.opening + "\n" + rows.join("\n") + "\n" + argument.input.closing)
}
catch(err){
if(!err.message.includes("cancelled")){
await new Alert(err.name, err.message).show()
}
throw `${err.name}\n${err.message}`
}
})();
Assign Tag Script
The following script iterates the selected tasks and assigns a specified tag of a tag set to each task, removing any existing tags from the tag set.
Assign Tag of Tag Set
allTags = flattenedTags
tagTitles = ["XXXXX", "YYYYY", "ZZZZZ"]
tagSet = new Array()
tagTitles.forEach(item => {
tag = allTags.byName(item) || new Tag(item)
tagSet.push(tag)
})
replacementTag = flattenedTags.byName("TTTTT")
document.windows[0].selection.tasks.forEach(task => {
task.removeTags(tagSet)
task.addTag(replacementTag)
})
And here is the script converted into an Omni Automation script URL that is edited and used with the column titles of the task status table to enable selected tasks to be assigned tags by clicking or tapping the column title link.
Encoded Assignment Script
omnifocus://localhost/omnijs-run?script=allTags%20%3D%20flattenedTags%0AtagTitles%20%3D%20%5B%22XXXXX%22%2C%20%22YYYYY%22%2C%20%22ZZZZZ%22%5D%0AtagSet%20%3D%20new%20Array%28%29%0AtagTitles%2EforEach%28item%20%3D%3E%20%7B%0A%09tag%20%3D%20allTags%2EbyName%28item%29%20%7C%7C%20new%20Tag%28item%29%0A%09tagSet%2Epush%28tag%29%0A%7D%29%0AreplacementTag%20%3D%20flattenedTags%2EbyName%28%22TTTTT%22%29%0Adocument%2Ewindows%5B0%5D%2Eselection%2Etasks%2EforEach%28task%20%3D%3E%20%7B%0A%09task%2EremoveTags%28tagSet%29%0A%09task%2EaddTag%28replacementTag%29%0A%7D%29
The placeholder TTTTT is replaced by the title of the tag from the tag set that is to be assigned to the selected tasks.
Task Status Table HTML
For reference, here is the HTML code for the Task Status Table webpage:
Task Status Table HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Status View</title>
<style>
body {background-color: #323232;}
#status-table {
font-size: normal;
color: black;
font-family: -apple-system, Helvetica, sans-serif;
font-style: normal;
width: 100%;
border-collapse: collapse;
}
#status-table a {text-decoration: none;}
#status-table tr td {
padding: 8px;
border-radius: 12px;
border: 2px solid #000;
}
#instructions {
color:white;
margin-top:36px;
margin-bottom: 36px;
text-align: center;
font-family: -apple-system, Helvetica, sans-serif;
font-size: 85%;
line-height: 100%;
}
</style>
</head>
<body>
<p id="instructions">TAP|CLICK column title to assign tag to selected task:</p>
<table id="status-table" style="margin-top:36px;">
<col style="background-color: #FAFFC7;" />
<col style="background-color: #FFCCE1;" />
<col style="background-color: #D7EEFF;" />
<tr>
<td style="font-size:150%;">
<a style="text-decoration:none;" href="omnifocus://localhost/omnijs-run?script=allTags%20%3D%20flattenedTags%0AtagTitles%20%3D%20%5B%22XXXXX%22%2C%20%22YYYYY%22%2C%20%22ZZZZZ%22%5D%0AtagSet%20%3D%20new%20Array%28%29%0AtagTitles%2EforEach%28item%20%3D%3E%20%7B%0A%09tag%20%3D%20allTags%2EbyName%28item%29%20%7C%7C%20new%20Tag%28item%29%0A%09tagSet%2Epush%28tag%29%0A%7D%29%0AreplacementTag%20%3D%20flattenedTags%2EbyName%28%22XXXXX%22%29%0Adocument%2Ewindows%5B0%5D%2Eselection%2Etasks%2EforEach%28task%20%3D%3E%20%7B%0A%09task%2EremoveTags%28tagSet%29%0A%09task%2EaddTag%28replacementTag%29%0A%7D%29">XXXXX</a>
</td>
<td style="font-size:150%;">
<a style="text-decoration:none;" href="omnifocus://localhost/omnijs-run?script=allTags%20%3D%20flattenedTags%0AtagTitles%20%3D%20%5B%22XXXXX%22%2C%20%22YYYYY%22%2C%20%22ZZZZZ%22%5D%0AtagSet%20%3D%20new%20Array%28%29%0AtagTitles%2EforEach%28item%20%3D%3E%20%7B%0A%09tag%20%3D%20allTags%2EbyName%28item%29%20%7C%7C%20new%20Tag%28item%29%0A%09tagSet%2Epush%28tag%29%0A%7D%29%0AreplacementTag%20%3D%20flattenedTags%2EbyName%28%22YYYYY%22%29%0Adocument%2Ewindows%5B0%5D%2Eselection%2Etasks%2EforEach%28task%20%3D%3E%20%7B%0A%09task%2EremoveTags%28tagSet%29%0A%09task%2EaddTag%28replacementTag%29%0A%7D%29">YYYYY</a>
</td>
<td style="font-size:150%;">
<a style="text-decoration:none;" href="omnifocus://localhost/omnijs-run?script=allTags%20%3D%20flattenedTags%0AtagTitles%20%3D%20%5B%22XXXXX%22%2C%20%22YYYYY%22%2C%20%22ZZZZZ%22%5D%0AtagSet%20%3D%20new%20Array%28%29%0AtagTitles%2EforEach%28item%20%3D%3E%20%7B%0A%09tag%20%3D%20allTags%2EbyName%28item%29%20%7C%7C%20new%20Tag%28item%29%0A%09tagSet%2Epush%28tag%29%0A%7D%29%0AreplacementTag%20%3D%20flattenedTags%2EbyName%28%22ZZZZZ%22%29%0Adocument%2Ewindows%5B0%5D%2Eselection%2Etasks%2EforEach%28task%20%3D%3E%20%7B%0A%09task%2EremoveTags%28tagSet%29%0A%09task%2EaddTag%28replacementTag%29%0A%7D%29">ZZZZZ</a>
</td>
</tr>
<!-- GENERATED ROWS GO HERE -->
</table>
</body>
</html>
Demo Setup Script
Here’s a script for creating demo content to try the shortcut:
Demo Setup Script
currentTags = flattenedTags
tagTitles = ["To Do", "Doing", "Done"]
tagTitles.forEach(tagName => {
currentTags.byName(tagName) || new Tag(tagName)
})
taskNames = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"]
taskNames.forEach(taskName => {
tagName = tagTitles[Math.floor(Math.random() * tagTitles.length)]
new Task("Task " + taskName).addTag(tagNamed(tagName))
})