Posted on :: Updated on :: Tags: , ,

Baby steps

A little while ago, I wrote a blog post about my first experience with Obsidian, more specifically with DataviewJS. ✍️ DataviewJS is an API in Obsidian that allows you to excute JavaScript and access the dataview indices and query engine. Basically, if the default Dataview query language to list, filter, sort or group data isn't enough for you, you're free to write your own logic. For me, the goal was to take all the time trackers created with the amazing ObsidianSimpleTimeTracker-plugin and show the worked hours per task or project. This worked, but not entirely in the tabular format I wanted. ❓

Fiddling

I was happy that my basic JavaScript fiddling worked, but it didn't yet provide me with what I needed: a solid overview of the hours worked per task or project, per day. As a security analyst I am increasingly more involved with various projects that require me to keep note of my worked hours. A table would be the optimal overview for what would be a very long list of data per worked day, over the course of multiple weeks and months. 👀

Execution flow

Eventually, I managed to fix my issue and organize the output of every daily time tracker in a single row, with formatted time values (xh, xxm xxs) per project or task. As I know in advance what my daily tasks are, I didn't have to make this part dynamic. But it did present me with the problem of how to have a row entry for each day, where I wasn't sure what project or task I worked on that day. Basically, if I have project 1, 2, 3 and 4, how can I make sure the table rows for Tuesday (worked only on project 1) and Thursday (worked on projects 2, 3 and 4) are the same? What helped me, was think it all through: what data do I want to represent in the table, what data type do I need for that, how (and when) in my logic will I fill that data? 💭

The way I did it

In the end, I chose for string values per entry name (name of a task or project) and their durations. Every time I iterate over an existing time tracker entry, I check for the entry name and fill the string value of the corresponding duration (entry_name == duration, socc_duration = getTickerEntryDuration, basically). Iterating over every existing tracker in my Obsidian vault, I first iterate over the individual tracker entries and fill the string variables as stated. Once this is done, I push these values to a premade JavaScript object, with key-value pairs like date: dateBasedOnObsidianNoteName, socc:socc_duration. Then, I build an Obsidian Dataview table with the dv.table() function, which I pass this dynamically updated JavaScript object, which then displays rows for each iterated tracker and its entries. 🏗️

The code

Enough jabbering, where's the code? Here it is, which results in this nice looking table, that displays best in a Canvas view.

The code:

let api = dv.app.plugins.plugins["simple-time-tracker"].api;


const duration = [{datum: '', socc: '', tdw: '', cloud: '', studie: '', pauze: ''}]

let entry_date = ''
let entry_name = ''
let entry_duration = ''

let socc_duration = ''
let cloud_duration = ''
let tdw_duration = ''
let studie_duration = ''
let pauze_duration = ''


for(let page of dv.pages('"tijd-bijhouden"').sort(p => p.file.name, 'desc')) {
	// load trackers in the file with the given path
	
	let trackers = await api.loadAllTrackers(page.file.path);
	
		if (trackers.length)
		
        for (let {section, tracker} of trackers) {
            let number_of_trackers = tracker.entries.length;
            for( let i = 0; i < number_of_trackers; i++) {
                if (tracker.entries[i])
                entry_date = page.file.name
                entry_name = tracker.entries[i]['name']
                if (entry_name == 'socc')
                    socc_duration = api.formatDuration(api.getDuration(tracker.entries[i]))
                else if (entry_name == 'cloud')
                  cloud_duration = api.formatDuration(api.getDuration(tracker.entries[i]))
                else if (entry_name == 'tdw')
                tdw_duration = api.formatDuration(api.getDuration(tracker.entries[i]))
                else if (entry_name == 'studie')
                studie_duration = api.formatDuration(api.getDuration(tracker.entries[i]))
                else if (entry_name == 'pauze')
                pauze_duration = api.formatDuration(api.getDuration(tracker.entries[i]))

		}

		duration.push({datum: page.file.name, socc: socc_duration, cloud: cloud_duration, tdw: tdw_duration, studie: studie_duration, pauze: pauze_duration})
}
}

dv.table(['datum', 'socc', 'cloud', 'tdw', 'studie', 'pauze'], duration.map(r => [r.datum, r.socc, r.cloud, r.tdw, r.studie, r.pauze]));

Edited screenshot of the code in action: