Unflag Available Tasks?

I’ve used Shortcuts a ton to automate omnifocus stuff for a long time, but have a desire that would only be able to be done by Omni Automation.

I don’t know how to script. Does anyone or could anyone put together an OmniFocus Automation that unflags all available tasks? (Or all available tasks that do or don’t have certain tags?)

I feel comfortable with editing an existing automation and trial and error. I’d like to use this in my morning review. Unflag everything to help me be deliberate about what I choose to flag for the day.

FWIW, this should get you started:

(() => {
	// main :: ()
	const main = () => {
	  const
	    availableTasks = flattenedTasks.
	      filter(x => Task.Status.Available === x.taskStatus);
	      
	   console.log(
	      `The number of available tasks is ${
	        availableTasks.length
	      }`  
	   )
	};

	return Application('OmniFocus')
        .evaluateJavascript(
            `(${main})()`
        );
})();

availableTasks is bound to an array of Task objects. Each of those, has a flagged property. Hence, a specific item flagged property could be changed with the following assignment:

availableTasks[0].flagged = false

To apply that assignment across the whole array, perhaps:

availableTasks.forEach(x => x.flagged = false)

It gives me an error when I try to run it and I don’t how anything about scripting to know how to proceed. I appreciate the effort though

TypeError: Application is not a function. (In ‘Application(‘OmniFocus’)’, ‘Application’ is an instance of CallbackObject) undefined:15:20

Sure. You should paste that code in, for example, Script Editor. And, set the language tab to JavaScript. This script should run in macOS. Of course, omniJS is a cross-platfrom API, so there should be a way of creating something similar for iOS/iPadOS.

I see that you ran the code in the Console. That’s why it gave the error.

(() => {
	const
	    availableTasks = flattenedTasks.
	      filter(x => Task.Status.Available === x.taskStatus);
	      
	   console.log(
	      `The number of available tasks is ${
	        availableTasks.length
	      }`  
	   )
})();

You can certainly run this version in the OmniFocus Automation Console.

Thank you for that, but pasting that into the console still gives me an error saying something is undefined.

Someone did point me toward this script. I tried messing with it for a while but I know nothing about any scripting language and could not figure out how to modify this script to only address ‘available’ tasks rather than ‘uncompleted’ ones. If you or anyone here would be able to do that to this script, that’d be helpful. If not, I at least feel I made an attempt to find an answer to this idea. Shortcuts can’t really modify an OF database, just query for data.

Here’s that script: https://github.com/ferlatte/omnifocus-plugins/blob/main/clear-flag-from-tasks.omnijs

Checked again, and the script works. Did you paste the whole code in the Console. We should be able to sort this out.

Thank you. When I run that in the console, I get two lines returned:

“The number of available tasks is 235”
and
“< undefined”

Good. The script works.

(() => {
	const
		availableTasks = flattenedTasks.
			filter(x => Task.Status.Available === x.taskStatus);
		
	// availableTasks.forEach(x => x.flagged = false)  
		console.log(
			`The number of available tasks is ${
				availableTasks.length
			}`  
		)
})();

I’ve commented the line that updates flagged property of the whole collection of tasks. This version could be run in the Console.

This gives me the same result, giving me the number of available tasks and saying ‘undefined.’

I don’t know what things mean in order to fiddle with it. Do you mean to say this script should replace something within the first one you posted?

I just meant that if you “uncomment” that line, i.e. remove the leading forward slashes…

availableTasks.forEach(x => x.flagged = false)

the script should accomplish what you want.

console.log is the last statement executed and it returns the value undefined. A more informative return value could be displayed, I think.

Hey, it works! Thanks so much.

1 Like

Revisited this today, and when I try to run this, it only seems to unflag available tasks that do not have due dates.

Just tried it and successfully un-flags available tasks that have (or don’t have) due dates.

Weird. I go to try it again and it does appear to work properly. I tried it several times this morning and got that result, though, so I am not sure what was wrong.

I am getting more confused. It will unflag some available tasks but not others. And it does seem to be depending on whether they have due dates. It’s so weird!

It’ll correctly omit unavailable tasks that have a future defer date or are blocked by sequential actions. And it’ll correctly unflag tasks that are available unless they have a due date. I’m not sure why that’d be. In scripting, does available mean the same thing it does in the GUI?

I don’t suppose a second script that targets tasks that are both available and have a due date would do it. Puzzling.

Well spotted !

I found the issue. I’ll post an update in a couple of days, after I finish some things. Meanwhile, if you want to play with it, a task with status due soon has a .taskStatus property DueSoon. I think you are able now to see why that is a problem. Available and DueSoon are distinct Class properties of Task.Status class.

Well that would explain it, including accounting for why it was not possible for me to see what other hidden meaning or property “available” would have in the realm of scripting.

I spent about an hour with Chat GPT and someone else’s script, and was able to cobble something that seems to work. Instead of facing the problem as you have spelled it out, we just found tasks that did not have any of the statuses besides Available. And then I had it modify further to exclude tasks belonging to a project or a tag that is on hold. Curious to see what you make of this, and whether any fix you cook up would be superior to this. This task also removes any Forecast Tag, although I am indifferent to this part of the script since I don’t use one. Author and such are unmodified by me.

/{
“author”: “Mark Ferlatte”,
“targets”: [“omnifocus”],
“type”: “action”,
“identifier”: “net.cryptio.clear-flag-from-tasks”,
“version”: “0.9”,
“description”: “Clear flag and forecast tag from uncompleted tasks.”,
“label”: “Clear flag and forecast tag from uncompleted tasks”,
“mediumLabel”: “Clear flag and forecast tag from uncompleted tasks”,
“paletteLabel”: “Clear flag and forecast tag from uncompleted tasks”,
}
/

/* Clear flags AND clear the forecast tag */

/* global PlugIn, flattenedTasks, Tag, Task, Project */

(() => {
var action = new PlugIn.Action(function() {
let tasks = flattenedTasks.filter(task => {
return ![
Task.Status.Completed,
Task.Status.Dropped,
Task.Status.Inactive,
Task.Status.OnHold,
Task.Status.Repeating,
Task.Status.RepeatingButDueSoon,
Task.Status.RepeatingButOverdue,
].includes(task.taskStatus) &&
(!task.deferDate || task.deferDate <= new Date()) &&
!(task.containingProject instanceof Project && task.containingProject.status === Project.Status.OnHold) &&
!task.tags.some(tag => tag.status === Tag.Status.OnHold);
});
tasks.forEach(task => {
task.flagged = false;
if (Tag.forecastTag) {
task.removeTag(Tag.forecastTag);
}
});
});

action.validate = function() {
return true;
};

return action;
})();

Oh, and to muddy things further, the problem I was having was not merely for tasks due soon, but that were available and had any due date, even one far off.