Skip to content

Instantly share code, notes, and snippets.

@csreed

csreed/OmniFocusDailyLog.js Secret

Last active Nov 16, 2019
Embed
What would you like to do?
Build a summary of tasks completed today
//
// 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. Do 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)
@jbeales

This comment has been minimized.

Copy link

@jbeales jbeales commented Oct 7, 2015

I thought I could clone & send a pull request back, but apparently not. On line 44 tasksWithNoProject is sometimes undefined for me, but since undefined != null it still tries to make a summary and crashes. Updating line 44 to if (tasksWithNoProject !== null && 'undefined' !== typeof tasksWithNoProject) { fixed the problem for me.

@csreed

This comment has been minimized.

Copy link
Owner Author

@csreed csreed commented Oct 7, 2015

Thanks, John! I’ve relaxed the type checking to just check for truthiness.

@torgerson

This comment has been minimized.

Copy link

@torgerson torgerson commented Oct 12, 2015

Fantastic! Thanks for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.