Skip to content

Commit 4dd5ed5

Browse files
committed
Add command to execute all computations over the hierarchically linked notes, from a root note defined in plugin's settings
1 parent dce167e commit 4dd5ed5

File tree

6 files changed

+99
-2
lines changed

6 files changed

+99
-2
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33
Welcome to TimeTree, an Obsidian plugin designed for structured, hierarchical task management and integrated time tracking using the Super Simple Time Tracker plugin.
44

55
This guide provides detailed steps for installing, configuring, and effectively using the TimeTree plugin within Obsidian.
6+
7+
## Recommended Forces in Graph View
8+
Repel and Link forces at maximum, Link distance at minimum, and Center force user's prefence.

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "time-tree",
33
"name": "Time Tree",
4-
"version": "0.0.1",
4+
"version": "0.0.2",
55
"minAppVersion": "0.15.0",
66
"description": "Track accumulated time spent on unlimited hierarchical tasks",
77
"author": "Lucas Lopes",

src/main.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ export default class TimeTreePlugin extends Plugin {
3535
await this.updateNodeSizeCommand();
3636
},
3737
});
38+
this.addCommand({
39+
id: "process-from-root",
40+
name: "Process Commands from Root Note",
41+
callback: async () => {
42+
await this.processFromRoot();
43+
},
44+
});
3845
}
3946

4047
async loadSettings(): Promise<void> {
@@ -306,4 +313,69 @@ export default class TimeTreePlugin extends Plugin {
306313

307314
new Notice("Node sizes updated for the active file and its descendants.");
308315
}
316+
async processFromRoot(): Promise<void> {
317+
const rootPath = this.settings.rootNotePath;
318+
if (!rootPath) {
319+
new Notice("Root note path is not configured in settings.");
320+
return;
321+
}
322+
323+
const rootFile = this.app.vault.getAbstractFileByPath(rootPath);
324+
if (!rootFile || !(rootFile instanceof TFile)) {
325+
new Notice("Root note file not found.");
326+
return;
327+
}
328+
329+
// Process elapsed time from the root note
330+
const localElapsed = await this.calculateRecursiveElapsedTime(rootFile);
331+
new Notice(`Updated recursive elapsed time: ${localElapsed}`);
332+
333+
// Process elapsed_child from the root note
334+
const totalElapsedChild = await this.calculateRecursiveElapsedChild(rootFile);
335+
const ownElapsed = (await this.getProperty(rootFile, "elapsed")) || 0;
336+
new Notice(`Updated elapsed_child for root note: ${totalElapsedChild - ownElapsed}`);
337+
338+
// Process node sizes from the root note and its descendants
339+
await this.updateNodeSizeFromRoot(rootFile);
340+
}
341+
342+
async updateNodeSizeFromRoot(rootFile: TFile): Promise<void> {
343+
// Gather all descendant files from the root note
344+
const descendantFiles = await this.gatherDescendantFiles(rootFile);
345+
const files = [rootFile, ...descendantFiles];
346+
347+
// Compute accumulated elapsed values for each file
348+
const accValues: { file: TFile, acc: number }[] = [];
349+
for (const file of files) {
350+
const elapsed = (await this.getProperty(file, "elapsed")) || 0;
351+
const elapsedChild = (await this.getProperty(file, "elapsed_child")) || 0;
352+
const acc = elapsed + elapsedChild;
353+
accValues.push({ file, acc });
354+
}
355+
356+
const accNumbers = accValues.map(item => item.acc);
357+
const minAcc = Math.min(...accNumbers);
358+
const maxAcc = Math.max(...accNumbers);
359+
360+
const min_d = 6;
361+
const max_d = 100;
362+
const A_min = min_d * min_d; // 36
363+
const A_max = max_d * max_d; // 10000
364+
365+
for (const { file, acc } of accValues) {
366+
let node_size: number;
367+
if (maxAcc === minAcc) {
368+
node_size = (acc === 0) ? min_d : max_d;
369+
} else {
370+
const A = A_min + ((acc - minAcc) / (maxAcc - minAcc)) * (A_max - A_min);
371+
node_size = Math.sqrt(A);
372+
}
373+
await this.updateProperty(file, (frontmatter) => {
374+
frontmatter.node_size = node_size;
375+
return frontmatter;
376+
});
377+
}
378+
379+
new Notice("Node sizes updated for the root note and its descendants.");
380+
}
309381
}

src/settings-tab.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,24 @@ export class TimeTreeSettingsTab extends PluginSettingTab {
2828
await this.plugin.saveSettings();
2929
});
3030
});
31+
new Setting(this.containerEl)
32+
.setName("Root Note Path")
33+
.setDesc("The path of the root note from which the commands will be executed.")
34+
.addText((text) => {
35+
text.setPlaceholder("Enter root note path")
36+
.setValue(this.plugin.settings.rootNotePath)
37+
.onChange(async (value) => {
38+
this.plugin.settings.rootNotePath = value;
39+
await this.plugin.saveSettings();
40+
});
41+
42+
// Create a datalist element for file suggestions
43+
const dataList = this.containerEl.createEl("datalist", { attr: { id: "file-datalist" } });
44+
const files = this.app.vault.getFiles();
45+
files.forEach(file => {
46+
dataList.createEl("option", { attr: { value: file.path } });
47+
});
48+
text.inputEl.setAttr("list", "file-datalist");
49+
});
3150
}
3251
}

src/settings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
export const defaultSettings: TimeTreeSettings = {
22
onlyFirstTracker: false,
3+
rootNotePath: ""
34
};
45

56
export interface TimeTreeSettings {
67
onlyFirstTracker: boolean;
8+
rootNotePath: string;
79
}

versions.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"0.0.1": "0.15.0"
2+
"0.0.1": "0.15.0",
3+
"0.0.2": "0.15.0"
34
}

0 commit comments

Comments
 (0)