New Draft with Calendar Details

Hi,

I’m hoping anyone can help me figure out a way to make an action to insert my current (or nearest) calendar entry into the title of the draft, optionally with details like the attendees. I often find myself opening a draft to take meeting notes and would be super handy if all those details were filled in for me.

I’m pretty sure I could figure out how to do this by creating a Shortcuts workflow that I kick off from Drafts. BUT I do most of my work these days on my trusty Mac, so I’m trying to figure out a way that works on Mac (or ideally both Mac and iOS equally.)

If it helps, I am a proud owner of Keyboard Maestro and Fantastical. I’ve searched around and can’t seem to find a way to get (rather than create) events using any of those tools. Fantastical seems to support AppleScript, but there isn’t great documentation around it, and I think it only lets you create events.

Any help would be really appreciated! To be honest, it’s odd I haven’t seen anyone else have a similar need out there? Seems like it would be a super handy Drafts action to have.

1 Like

Have you looked at the Calendar functionality in the scripting documentation?

https://scripting.getdrafts.com/classes/calendar

The read example gives you a great starting point.

Hi, I have made this for myself in combination with Shortcut. You can read about this here, including a video and download to the used Shortcuts and Action groups.

1 Like

That looks awesome! Unfortunately, I am looking for something that will work for a Mac, so I don’t think Shortcuts will fit the bill.

Boom. Didn’t even think to look at that. Native Drafts functions seems to be the cleanest way to do that. I hope that works on a Mac though; so far my research tells me that the calendar APIs on MacOS are very different; most of the examples I saw resort to AppleScript to interact with the calendar.

Drafts calendar scripting is cross-platform.

Awesome! Okay, this is my weekend project. I’m really hoping I can tackle this without asking you and @sylumer a million questions to fix my terrible code.

Okay, so I am really stuck here. I’m just playing around with the Calendar functionality to see if I can get some events back and add to a draft to start. With the below, my appts variable stays as “Nothing”. The below is a little modified from the example script as a POC:

// load a calendar
let cal = Calendar.default();

//create variable that will update the draft 
let appts = "Nothing"

//get all events in last 30 days and add to appts
if (cal) {
let events = cal.events((30).days().ago(), new Date());
for (let event of events) {
    appts = appts+event.title;
}
}
//add result to draft 
draft.content = draft.content+appts;
draft.update()

(I know I don’t want “Nothing” to appear in the final version of this, it’s just a placeholder to see if I get anything back.

Here would be my take:

// Initialise
let calDefault = Calendar.default();
let astrAppointments = [];

// Grab events from last 30 days (based on current time) and append them to an array
let aev = calDefault.events(Date.today().addDays(-30) , Date.today());
aev.map(ev => astrAppointments.push(ev.title));

// If we found events, add them to the current draft
if(astrAppointments.length > 0)
{
	draft.content = draft.content + "\n" + astrAppointments.join("\n");
	draft.update();
}
else app.displayWarningMessage("No events found");

I think the issue in your code is something taken from the example in the scripting docs.

For me this test code below gives me ‘now’ rather than 30 days ago, which means that any search between that date and now is always going to be a rather more limited set of events.

alert((30).days().ago());

I know that DateJS that Drafts uses is supposed to support that syntax, but it doesn’t seem to be working (neither is fromNow() when I tried that with similar syntax). I also tried both singular and plural forms for day and no luck with any of them.

Maybe the is a Drafts issue with utilising the DateJS library? But, whatever the case, date arithmetic is something there are many ways to deal with.

Ah, I didn’t even think to check whether the date math was working. So I actually wanted only the current event that is on my calendar for this. A little tricky when dealing with some events that could be an hour, some that could be 15 minutes, what time it is currently, etc. Anyway, modified yours a little bit and this seems to be working with most of my tests now.

I also had to change “Date.today” to “Date.now” (took a guess that would work) to limit to current exact time.

And I changed the variable name to something a little friendlier to my brain. :upside_down_face:

// Initialise
let calDefault = Calendar.default();
let foundAppointments = [];
let eventsCount = 0

// Grab events from last 3 hours (based on current time) and append them to an array
let aev = calDefault.events(Date.today().addMinutes(-180), Date.now());
aev.map(ev => foundAppointments.push(ev.title));

for (const foundAppointment of foundAppointments){
	eventsCount = eventsCount +1;
}

// Get the latest event found and add to drafts with a markdown title
if(foundAppointments.length > 0)
{
	draft.content = draft.content + "# " + foundAppointments [eventsCount-1] + "\n";
	draft.update();
}
else app.displayWarningMessage("No events found");

Of course, more than happy if you can point out any flaws in my logic here that I didn’t catch.

This wasn’t sitting right with me. Updated the script to prepend the title automatically. (My use case is I often start just writing down notes in Drafts and realize halfway through I should write a title with the current meeting invite so I know what the hell the context of the notes was.)

// Initialise
let calDefault = Calendar.default();
let foundAppointments = [];
let eventsCount = 0

// Grab events from last 3 hours (based on current time) and append them to an array
let aev = calDefault.events(Date.today().addMinutes(-180), Date.now());
aev.map(ev => foundAppointments.push(ev.title));

for (const foundAppointment of foundAppointments){
	eventsCount = eventsCount +1;
}

// Get the latest event found and add to drafts with a markdown title
if(foundAppointments.length > 0)
{
	draft.prepend ("# " + foundAppointments [eventsCount-1] + "\n");
	draft.update();
}
else app.displayWarningMessage("No events found");

A few suggestions.

foundAppointments.length = eventsCount, so I don’t think you have need of the latter and its code to set it up.

There is a reliance on the events method returning the calendar events in a sorted order. Technically there is nothing in the docs to confirm that the results are always ordered chronologically. Should you find at some point this gives you the wrong result, consider an additional step such as sorting the array of events by the startDate property, or grabbing all of the event dates, sorting them, finding the most recent, and then matching that to the property of an event to find the most recent.

Sometimes, I have multiple entries in my calendar that start at the same time. If this is something you also have, consider offering a prompt to select the desired calendar event.

Ah, that is a good point on the redundant check.

I’ll see how it goes this week regarding the sorting of and simultaneous events (sadly, I have those as well) and adjust based on that.