/
pick.js
133 lines (133 loc) · 4.91 KB
/
pick.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
"use strict";
(() => {
function weightedRandom(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;
}
class FlagTasks {
constructor(wantFlagged, tagWeights) {
this.tagWeights = tagWeights;
this.tasks = 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));
this.wantFlagged = wantFlagged;
this.currentlyFlagged = this.tasks.filter((t) => t.flagged).length;
}
enact() {
if (this.currentlyFlagged >= this.wantFlagged) {
console.log(`we have ${this.currentlyFlagged} tasks, and want ${this.wantFlagged}, so we're just done.`);
return;
}
let now = new Date();
let weightedTasks = [];
for (let task of this.tasks) {
// start with weights from tags
let weight = this.tagWeightsForTask(task);
if (!weight) {
console.log(`skipping ${task.name} because no tags matched.`);
continue;
}
// tasks that are closer to their due date should be weighted higher, up
// to three weeks out
if (task.effectiveDueDate) {
weight += Math.max(0, 21 - this.daysBetween(now, task.effectiveDueDate));
}
// tasks that have been deferred should grow in urgency from their
// deferral date. This includes repeating tasks! Otherwise, they should
// grow in urgency according to when they were created. If both dates
// are somehow null, it's OK to not add any weight to the task.
weight += Math.max(14, this.daysBetween(now, task.effectiveDeferDate || task.added || now));
weightedTasks.push([task, weight]);
}
if (weightedTasks.length === 0) {
new Alert("Problem choosing tasks", "Weighted tasks array was empty!").show();
return;
}
while (this.currentlyFlagged < this.wantFlagged &&
weightedTasks.length >= 1) {
let next = null;
while (!next || next.flagged) {
next = weightedRandom(weightedTasks);
}
next.flagged = true;
this.currentlyFlagged++;
weightedTasks = weightedTasks.filter(([task, _]) => task.id !== next?.id);
}
}
tagWeightsForTask(task) {
// we return a null weight if no tags match, because we don't want to
// choose tasks that don't match any tags.
var weight = null;
var todo = task.tags;
var seen = [];
while (todo.length !== 0) {
let tag = todo.pop();
if (seen.indexOf(tag) !== -1) {
continue;
}
if (this.tagWeights[tag.name]) {
weight = (weight || 0) + this.tagWeights[tag.name];
}
if (tag.parent) {
todo.push(tag.parent);
}
seen.push(tag);
}
return weight;
}
daysBetween(a, b) {
let millis = Math.abs(a.getTime() - b.getTime());
return millis / 1000 / 60 / 60 / 24;
}
}
function isDuringWorkHours() {
const now = new Date();
const hour = now.getHours();
const day = now.getDay();
return hour >= 8 && hour <= 17 && day != 0 && day != 6;
}
var action = new PlugIn.Action(async () => {
try {
let weights = {};
if (isDuringWorkHours()) {
weights = {
work: 4,
Kraken: 2,
"Wandering Toolmaker": 2,
"from Linear": 8,
"from GitHub": 8,
habit: 10,
personal: 1,
};
}
else {
weights = {
Anne: 10,
personal: 4,
hobbies: 2,
house: 2,
learning: 6,
};
}
new FlagTasks(5, weights).enact();
}
catch (err) {
console.error(err);
throw err;
}
});
return action;
})();