”Completed Tasks” to build a simple text loggfile- =SOLVED_!

Hi and good day,

How would one use ”Completed Tasks” to build a simple text loggfile of completed tasks with creation/ or due dates?

(Before Apple blocked AppleScript on macOS I had a script which was doing it. - We need to write to Apple to do something about AppleScript.)

It looked like this (here was no entry.)

.

===== 2022-03-04 =====

No tasks completed. Done something without writing it down?

.

.

/

with best regards, Omar KN, Sweden

Not sure what you mean by “Apple blocking AppleScript” — AS is alive and well in MacOS and I run AppleScripts controlling OF daily. Can you share the script that has stopped working for you?

NB: This is a JS script, which I missed.
Now it works, the path (set after the script) was wrong.

But if Applescript works for you this would be good news. There are a lot of users who have complained about it, and all of the scripts don’t work anymore. Which OS do you use?

mine is Mac OS 10.14.6
OF 3.11.6

        • the script -is JScript - - - - - - - - - - - - - - - - - - - - - - - - -
//
//  Build a summary of OmniFocus tasks completed today.
//
//  This is intended to be run as a TextExpander macro,
//  but will work anywhere you can invoke a JS script.
//
//  v 1.0.2 (full release history at bottom)

var NoProjectMarker = "No Project";

getTaskSummary();

function getTaskSummary() {
	var doc = Application('OmniFocus').defaultDocument;

	var thisMorning = startOfDay();

	var tasks = doc.flattenedTasks.whose({completionDate: {'>=':thisMorning} })();
	if (tasks.length == 0) {
		return "No tasks completed. Done something without writing it down?";
	}
	
	// Group tasks by project, then extract progressed projects (projects with
	// completed tasks) from allProjects. This gives us the list of projects
	// in the same order as OmniFocus’s UI.
	var groupedTasks = groupArrayByKey(tasks, function(v) {
		var proj = v.containingProject();
		if (proj) {
			return proj.id();
		}
		return NoProjectMarker;
	});

	var allProjects = doc.flattenedProjects();
	var progressedProjects = allProjects.filter(function(p) {
		return p.id() in groupedTasks;
	});
	
	// Build the summary
	var summary = progressedProjects.reduce(function(s,p){
		return s + summaryForProject(p);
	}, "");
	
	var tasksWithNoProject = groupedTasks[NoProjectMarker];
	if (tasksWithNoProject) {
		summary += summaryForTasksWithTitle(tasksWithNoProject, "No Project\n");
	}
	
	return summary;

	// This needs to be in this scope because it captures groupedTasks
	function summaryForProject(p) {
		var projectID = p.id();
		var tasks = groupedTasks[projectID].filter(function(t) {
			return projectID != t.id(); // Don't include the project itself
		});
		return summaryForTasksWithTitle(tasks, projectSummaryLine(p));
	}
	function summaryForTasksWithTitle(tasks, title) {
		return title + tasks.reduce(summaryForTasks,"") + "\n";
	}
}

// Reducing function to summarize a list of tasks
function summaryForTasks(s,t) {
	return s + lineForTask(t);
}

// Create a summary line for a project
function projectSummaryLine(project) {
	var tokens = [];
	tokens.push(project.name());
	
	var remainingStatus = remainingStatusForProject(project);
	if (remainingStatus != "") {
		tokens.push("(" + remainingStatus + ")");
	}
	
	return tokens.join(" ") + "\n";
}

// This is appended to the end of a project line
function remainingStatusForProject(project) {
	if (!project.completedByChildren()) {
		return "";
	}
	var remainingCount = project.numberOfTasks() - project.numberOfCompletedTasks();
	if (remainingCount == 0) {
		return "complete";
	}
	
	return remainingCount + " remaining";
}

function lineForTask(task) {
	return " ✓ " + task.name() + "\n";
}

// Group an array of items by the key returned by this function
function groupArrayByKey(array,keyForValue) {
	var dict = {};
	for (var i = 0; i < array.length; i++) {
		var value = array[i];
		var key = keyForValue(value);
		if (!(key in dict)) {
			dict[key] = [];
		}
		dict[key].push(value);
	}
	return dict;
}

function startOfDay() {
// The day started at midnight this morning
	var d = new Date();
	d.setHours(0);
	d.setMinutes(0);
	d.setSeconds(0);
	return d;
}

// Release History
// 1.0   Initial release
// 1.0.1 Fix for tasks without a project
// 1.0.2 Relaxed the type checking (!== is too strict)

Ok this is a JS script.
• WAIT, I think the path is wrong.

But all AScr. don’t work anyway.

/

with best regards, Omar KN, Sweden

I think it receives less attention these days as of course AS is Mac only — automations based on Omni’s JS can run on iPad and iPhone too — but both OF3 and indeed the OF4 beta on Mac remain Apple scriptable

For anyone interested how to create an OF logfile:

I’m using KeyboardMaestro with
1st. this Javascript to collect the latest OF completed tasks , then

2nd. the result from the Jscript is put into a variable (for ex. VarOFL) and then appended to the logfile… .txt

PS: I would have included the creator of this script, if I had known the name, he deserves credit.
/

with best regards, Omar KN

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.