missions | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
const {DvGoalsProgress} = customJS;
const missions = dv.current().missions
await DvGoalsProgress.getProgress({dv}, missions, [1, 7, 30], false)
/** | |
Tracks mission-related KPIs (goals) targets from daily notes. | |
Daily notes' frontmatter structure: | |
``` | |
--- | |
mission: | |
220_01_332: | |
water: 2000 | |
sleep: 360 | |
--- | |
``` | |
*/ | |
class DvGoalsProgress { | |
async getProgress(args, missions, days, folded) { | |
const {dv} = args | |
const foldSymbol = folded ? "-" : "+" | |
let out = '> [!multi-column]\n' | |
for (const nDays of days) { | |
const header = nDays === 1 ? "Today's KPIs" : nDays + " Days KPIs" | |
out = out + '>\n' | |
out = out + '> > [!info]' + foldSymbol + ' ' + header + '\n> >\n' | |
out = out + '> > |KPI|Daily Avg.|' + (nDays === 1 ? 'Target (Today) ' : 'Target (Day/Period)') + '|Progress|\n'; | |
out = out + '> > |---|---|---|---|\n'; | |
for (const mission of missions) { | |
out = out + await this._getGoalsAverage(args, nDays, mission); | |
} | |
} | |
dv.paragraph(out); | |
} | |
async _getGoalsAverage(args, nDays, mission) { | |
const {app, dv, that} = args | |
const missionId = mission.id | |
const kpis = mission.kpis | |
const columns = kpis.map(kpi => "round(sum(nonnull(rows.M." + kpi.name + ")) / " + nDays + ", 2) as \"" + kpi.name + "\"").join(", ") | |
const dvQuery = ` | |
TABLE WITHOUT ID | |
` + columns + ` | |
FROM #daily | |
WHERE 1=1 | |
AND date(today) - file.day < dur(` + nDays + ` days) | |
FLATTEN mission["` + missionId + `"] AS M | |
GROUP BY true | |
` | |
const qryAvg = await dv.query(dvQuery) | |
let avgValues = qryAvg.value.values; | |
let avgTable = []; | |
for (let r of avgValues) { | |
kpis.forEach(({goal, name, unit}, i) => { | |
const avg = r[i]; | |
const percentOfGoal = Math.round(avg * 100 / goal); | |
let progressBar = '<progress value="' + percentOfGoal + '" max="100"></progress>' | |
avgTable.push([name + " (" + unit + ")", avg, goal, percentOfGoal, progressBar]); | |
}) | |
} | |
let out = ''; | |
for (let r of avgTable) { | |
let kpi = r[0]; | |
let dailyAvg = r[1]; | |
let dailyTarget = r[2]; | |
let periodTarget = dailyTarget * nDays; | |
let percent = r[3]; | |
let bar = r[4]; | |
out = out + '> > |' + kpi + '|' + dailyAvg + '|' + (nDays === 1 ? dailyTarget : dailyTarget + '/' + periodTarget) + '|' + bar + '|\n'; | |
} | |
return out | |
} | |
} |
missions | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
const {DvGoalsProgress} = customJS;
const missions = dv.current().missions
await DvGoalsProgress.getProgress({dv}, missions, [1, 7, 30], false)