choose a random task

picker-v2
Brian Hicks 2022-10-13 20:42:03 -05:00
parent 4544efa7c6
commit 632bc3f2d6
Signed by: brian
GPG Key ID: C4F324B9CAAB0D50
9 changed files with 218 additions and 2 deletions

View File

@ -0,0 +1 @@
"zone.bytes.gardening" = "Digital Gardening for Omnifocus";

View File

@ -0,0 +1,5 @@
"label" = "Pick Something";
"shortLabel" = "Pick";
"mediumLabel" = "Pick Something";
"longLabel" = "Pick Something";
"paletteLabel" = "Pick";

View File

@ -0,0 +1,88 @@
"use strict";
(() => {
let creds = new Credentials();
var getWeights = function () {
const now = new Date();
const hour = now.getHours();
const day = now.getDay();
if (hour >= 8 && hour <= 17 && day != 0 && day != 6) {
return { work: 0.8, personal: 0.2 };
}
else {
return { work: 0.8, personal: 0.2 };
return { work: 0.0, personal: 1.0 };
}
};
var categorizeTask = function (task) {
var todo = task.tags;
while (todo.length != 0) {
let tag = todo.pop();
if (tag.name == "work") {
return "work";
}
else if (tag.name == "personal") {
return "personal";
}
else if (tag.parent) {
todo.push(tag.parent);
}
}
return null;
};
var daysBetween = function (a, b) {
let millis = Math.abs(a.getTime() - b.getTime());
return millis / 1000 / 60 / 60 / 24;
};
var weightedRandom = function (pairs) {
var total = 0;
for (let pair of pairs) {
total += pair[1];
}
let target = Math.random() * total;
for (let pair of pairs) {
target -= pair[1];
if (target <= 0) {
return pair[0];
}
}
return null;
};
var chooseATask = function () {
let weights = getWeights();
let now = new Date();
let possibleTasks = flattenedProjects
.filter((p) => p.status == Project.Status.Active)
.flatMap((p) => p.flattenedTasks.filter((t) => t.taskStatus == Task.Status.Available ||
t.taskStatus == Task.Status.DueSoon ||
t.taskStatus == Task.Status.Next ||
t.taskStatus == Task.Status.Overdue));
let weightedTasks = [];
for (let task of possibleTasks) {
// weight some categories higher than others
let categoryWeight = 0;
let category = categorizeTask(task);
if (category) {
categoryWeight = weights[category];
}
// weight stale-er tasks higher, up to 7 days
let ageWeight = Math.min(7, daysBetween(now, task.modified)) / 7;
// weight due-er tasks higher, up to 100 points
let dueWeight = 0;
if (task.effectiveDueDate) {
dueWeight = 100 - daysBetween(now, task.effectiveDueDate);
}
weightedTasks.push([task, ageWeight + dueWeight + categoryWeight]);
}
return weightedRandom(weightedTasks);
};
var action = new PlugIn.Action(async () => {
try {
console.log(`task: ${chooseATask()}`);
}
catch (err) {
console.error(err);
throw err;
}
});
return action;
})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,108 @@
(() => {
let creds = new Credentials();
var getWeights = function (): { work: number; personal: number } {
const now = new Date();
const hour = now.getHours();
const day = now.getDay();
if (hour >= 8 && hour <= 17 && day != 0 && day != 6) {
return { work: 0.8, personal: 0.2 };
} else {
return { work: 0.8, personal: 0.2 };
return { work: 0.0, personal: 1.0 };
}
};
var categorizeTask = function (task: Task): "work" | "personal" | null {
var todo = task.tags;
while (todo.length != 0) {
let tag = todo.pop();
if (tag.name == "work") {
return "work";
} else if (tag.name == "personal") {
return "personal";
} else if (tag.parent) {
todo.push(tag.parent);
}
}
return null;
};
var daysBetween = function (a: Date, b: Date): number {
let millis = Math.abs(a.getTime() - b.getTime());
return millis / 1000 / 60 / 60 / 24;
};
var weightedRandom = function <Type>(pairs: [Type, number][]): Type | null {
var total = 0;
for (let pair of pairs) {
total += pair[1];
}
let target = Math.random() * total;
for (let pair of pairs) {
target -= pair[1];
if (target <= 0) {
return pair[0];
}
}
return null;
};
var chooseATask = function (): Task | null {
let weights = getWeights();
let now = new Date();
let possibleTasks = flattenedProjects
.filter((p) => p.status == Project.Status.Active)
.flatMap((p) =>
p.flattenedTasks.filter(
(t: Task) =>
t.taskStatus == Task.Status.Available ||
t.taskStatus == Task.Status.DueSoon ||
t.taskStatus == Task.Status.Next ||
t.taskStatus == Task.Status.Overdue
)
);
let weightedTasks: [Task, number][] = [];
for (let task of possibleTasks) {
// weight some categories higher than others
let categoryWeight = 0;
let category = categorizeTask(task);
if (category) {
categoryWeight = weights[category];
}
// weight stale-er tasks higher, up to 7 days
let ageWeight = Math.min(7, daysBetween(now, task.modified)) / 7;
// weight due-er tasks higher, up to 100 points
let dueWeight = 0;
if (task.effectiveDueDate) {
dueWeight = 100 - daysBetween(now, task.effectiveDueDate);
}
weightedTasks.push([task, ageWeight + dueWeight + categoryWeight]);
}
return weightedRandom(weightedTasks);
};
var action = new PlugIn.Action(async () => {
try {
console.log(`task: ${chooseATask()}`);
} catch (err) {
console.error(err);
throw err;
}
});
return action;
})();

View File

@ -0,0 +1,13 @@
{
"author": "Brian Hicks",
"identifier": "zone.bytes.gardening",
"defaultLocale": "en",
"version": "1.0",
"description": "Digital Gardening in OmniFocus",
"actions": [
{
"identifier": "pick",
"image": "pick.png"
}
]
}

View File

@ -25,3 +25,4 @@ Except for third-party icons and assets listed below, this code is released unde
Exceptions:
- The Linear logo icon is provided by [Linear in their Brand Guidelines](https://linear.app/docs/brand-guidelines) section, and does not have a license listed.
- Other image icons from [Josh Hughes](https://omnifocusicons.josh-hughes.com/), licensed under "Please feel free to use the icons as you see fit"

View File

@ -9,6 +9,6 @@
let pkgs = import inputs.nixpkgs { inherit system; };
in {
devShell =
pkgs.mkShell { packages = [ pkgs.nodePackages.typescript ]; };
pkgs.mkShell { packages = [ pkgs.nodePackages.typescript pkgs.nodePackages.prettier ]; };
});
}

View File

@ -12,7 +12,7 @@
/* Language and Environment */
"target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"lib": ["es7"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"lib": ["es2019"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */