Just wanted to a share a dataview/templater combo I'm using to create notes from events. #120
The1029
started this conversation in
Show and tell
Replies: 2 comments 1 reply
-
|
Hello! I like very much your workflow but it seems something has broken after a while I haven't used. I get an "invalid date" value in start and end in dataview. Here's my code modified to my needs (slightly). Could you help me? |
Beta Was this translation helpful? Give feedback.
1 reply
-
|
Thanks a lot, I’ll give it a try!
… Il giorno 8 giu 2025, alle ore 01:16, The1029 ***@***.***> ha scritto:
Hey, glad you are liking! This was made for an older version of ICS. When this setup broke, I took the oppourtunity to update what I was running and added calendar-specific grouping and processing (eg: I have birthdays set to link to that person's note rather than create a standard event note). It also pulls upcoming events thanks to ICS's new functionality. This works with 1.10.1 (latest version at time of writing). I hope this helps!
// Prevents a bunch of errors every time you open your daily template - change `'daily'` to whatever your template is called.
if (dv.current().file.name === 'daily') {
dv.el('div', 'Editing template...');
return;
}
const icsPlugin = app.plugins.getPlugin('ics');
const inNextDays = 7; // This number dictates how many upcoming days to pull.
const thisWeek = Array.from({length: inNextDays}).map((_, weekday) => moment(dv.current().file.name).add(weekday, 'd').format("YYYY-MM-DD"));
const events = (await icsPlugin.getEvents(...thisWeek)).map(e => {
let calendar = e.icsName;
let startDate = moment(e.time);
let endDate = moment(e.endTime);
let startStr = '';
let endStr = '';
let title = '';
// This block is where calendar-specific actions are handled. If you don't need / want this, you can remove most of it and just keep the contents of the "else" block, which will parse all events identically.
if (calendar === 'Birthdays') {
title = dv.fileLink(`People/${e.summary}`, false, e.summary);
startStr = startDate.format('DD-MM-YYYY');
endStr = endDate.format('DD-MM-YYYY');
} else if (calendar === 'Holidays') {
title = dv.fileLink(`Events/Holidays/${e.summary}`, false, e.summary);
startStr = startDate.format('DD-MM-YYYY');
endStr = endDate.format('DD-MM-YYYY');
} else {
title = dv.fileLink(`Events/${startDate.format('YYYY')}/${startDate.format('MM-MMM')}/${startDate.format('YYYY-MM-DD')} - ${e.summary}`, false, e.summary);
// Check if all day event, format appropriately.
if (startDate.format('HH:mm') === '00:00' && endDate.format('HH:mm') === '00:00') {
startStr = startDate.format('DD-MM-YYYY');
endStr = endDate.subtract(1, 'days').format('DD-MM-YYYY');
} else {
startStr = startDate.format('HH:mm - DD-MM-YYYY');
endStr = endDate.format('HH:mm - DD-MM-YYYY');
}
}
// I also added this as a visual cue for each calendar. Again, you can remove this if not needed.
let titleWithIcon = '';
switch (calendar) {
case 'Home':
titleWithIcon = '🏠 ' + title;
break;
case 'Work':
titleWithIcon = '💼 ' + title;
break;
case 'Birthdays':
titleWithIcon = '🎂 ' + title;
break;
case 'Holidays':
titleWithIcon = '🗓️ ' + title;
break;
}
return {
titleWithIcon, // If you removed icons, remember to delete this line too as 'titleWithIcon' won't be present. You'll also need to look through table maps below.
title,
startStr,
endStr,
startDate,
calendar
}
});
events.sort((a, b) => {
if (a.startDate.isBefore(b.startDate)) return -1;
if (a.startDate.isAfter(b.startDate)) return 1;
if (a.title < b.title) return -1;
if (a.title > b.title) return 1;
return 0;
});
let ongoingEvents = [];
let upcomingEvents = [];
let birthdays = [];
events.forEach(e => {
if (e.calendar === 'Birthdays') {
birthdays.push(e);
return;
}
if (moment(dv.current().file.name).isBetween(e.startDate, e.endDate, "day")) {
ongoingEvents.push(e);
return;
}
if (moment(dv.current().file.name).isSame(e.startDate, "day")) {
ongoingEvents.push(e);
return;
}
upcomingEvents.push(e);
});
dv.header(3, 'Today');
if (ongoingEvents.length === 0) {
dv.el('div', 'No events today.');
} else {
dv.table(
["Event", "Start", "End"],
ongoingEvents.map(e => [
e.titleWithIcon,
e.startStr,
e.endStr
])
);
}
dv.header(3, 'Upcoming');
if (upcomingEvents.length === 0) {
dv.el('div', `No events in next ${inNextDays} days.`);
} else {
dv.table(
["Event", "Start", "End"],
upcomingEvents.map(e => [
e.titleWithIcon,
e.startStr,
e.endStr
])
);
}
dv.header(3, 'Birthdays');
if (birthdays.length === 0) {
dv.el('div', `No birthdays in next ${inNextDays} days.`);
} else {
dv.table(
["Person", "Date", "To Go"],
birthdays.map(e => [
e.startDate.diff(moment(dv.current().file.name), 'days') === 0 ?`**${e.titleWithIcon}**` : e.titleWithIcon,
e.startDate.diff(moment(dv.current().file.name), 'days') === 0 ?`**${e.startStr}**` : e.startStr,
e.startDate.diff(moment(dv.current().file.name), 'days') === 0 ? '🎉' : `${e.startDate.diff(moment(dv.current().file.name), 'days')} day${e.startDate.diff(moment(dv.current().file.name), 'days') === 1 ? '' : 's'}`
])
);
}
—
Reply to this email directly, view it on GitHub <#120 (reply in thread)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AS4F26DM4XNIKAPU7V5GUCT3CNXDTAVCNFSM6AAAAAB6Z6EBX6VHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTGMZZHE3DSNY>.
You are receiving this because you commented.
|
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Introduction
This combo creates a table view of events in your daily note with clickable links to create notes on demand. I use this when attending conferences/meetings to take notes in Obsidian.
If you already have notes in the "description" field in your calendar, these will be pulled into the body of the note at the time that it's created. The templater setup "fails gracefully", so if you create a fresh event in Obsidian without pulling from a calendar, it will give you blank fields instead of errors.
Be Aware: This simply creates a note and pulls in the data once, it is not a two-way sync. Updates to event times/descriptions made in Obsidian will not be reflected in your calendar, and vice-versa. If you make changes in your calendar and want them reflected in Obsidian, you will either have to do this manually, or delete the note and create it again.
Obligatory disclaimer: it works on my machine! I hope you don't run into issues, but if it doesn't work please ensure you have everything setup as described below. This assumes you have some knowledge of JavaScript, as well as Templater and Dataview. If you don't, you should! Please check their docs and YouTube for tutorials. I accept no responsibility for any loss of data/problems you run into - test in a fresh vault first if you're unsure.
Setup
You will need to create an
Eventsfolder if you don't already have one. You'll also need to create a template calledevent.md. If you'd rather use different names/locations, just edit the code below to point to your destinations of choice.In Templater, you'll need to enable Folder templates, and set one up so that any new notes created in your
Eventsfolder use theevent.mdtemplate.In the ICS settings, set your time format to
YYYY-MM-DDTHH:mmlike this:This is the default format expected by moment.js.
You will also need to have javascript queries enabled in Dataview, if you don't already.
Notes Content
Place this where you want it in your daily note. If your daily template is not called
daily, change the value in the firstifstatement. See moment.js docs for more info on how to modify date formats.And place this in your
event.mdtemplate. I usetype: eventin my metadata, but if you prefer tags you can modify appropriately.And you're all set! When you create the note, it will take a few seconds to pull from your remote calendar (as it does to load events in the first place), but be patient and they should appear. If you only get blank metadata fields with calendar set to
obsidian, templater has not found the event - check you have everything setup correctly.Beta Was this translation helpful? Give feedback.
All reactions