2 min read

Weekly Update #12

Hi Friends,

Another week in New York City without any snow. I'm beginning to think we might go the whole winter and not see a respectable storm. A damn shame, if you ask me.

Lack of snow didn't stop us from having a great time ice skating at the Bryant Park Winter Village on Saturday, though. You can book a ticket online for free, and if you have your own skates you can just show up and hop on the ice. We don't have our own skates, however, so we paid $25 each to rent them for the hour. It was super fun! The Winter Village is cute and cozy, nestled among the skyscrapers in Midtown. There are little food stalls selling hot meals and drinks to the skaters and villagers.

The Green Machine

I started making a new type of smoothie this week, it's called The Green Machine. Ingredients are

  • 1 banana
  • 1 cup frozen mango
  • 2 cups spinach
  • 2 tbsp. chia seeds
  • 1 cup orange juice

It's delicious and the perfect refreshing drink to have after a hard workout. I also like to make it early in the morning as a light breakfast to get my day started.

Notion Plugin

This weekend I wrote a small Notion extension[1] to enhance my life management system, which I've described in the past. The problem I had is that on each task item I keep two different "status" properties. One is more for organization and prioritization. It follows the status guidance from the Getting Things Done system, so the values are:

  1. Inbox
  2. Next
  3. Calendar
  4. Waiting
  5. Someday/Maybe
  6. Done
  7. Cancelled

This property is what determines which views an item shows up in.

The other status property tracks progress on a task that I've decided to pick up and work on. So the values are just

  1. Todo
  2. In Progress
  3. Done
  4. Cancelled

This leads to the situation where when I mark the status of a task to Done, I have to update both properties. But I only want to update one property!

Conveniently, Notion provides an API for programming your own extensions. I read their API docs on Saturday evening and wrote a small script that checks for items where one status property is Done, but not the other. Then it automatically updates the other status property to be Done so they stay in sync.

The script is a long-running service that pings the Notion servers once a second, so the updates happen in real time as you are making them. I've just been running it in the background on my laptop, but will probably deploy it to my home server at some point this week.


Alright, it's getting late on Sunday and I'd like to take the rest of the evening to relax so that I can get to bed on time and wake up early tomorrow to start the week with a good workout.

Stay safe and see you next week ❤️


[1] Here's the script for anyone curious.

import { Client, isFullPage } from "@notionhq/client";
import { PageObjectResponse, PartialPageObjectResponse } from "@notionhq/client/build/src/api-endpoints";


const notion = new Client({
  auth: process.env.NOTION_TOKEN,
});

const sleep = (ms: number) => new Promise(r => setTimeout(r, ms))

async function setPageDone(page: PageObjectResponse) {
  console.log(`setting page ${page.id} Done`)

  await notion.pages.update({
    page_id: page.id,
    properties: {
      Pipeline: {
        status: {
          name: 'Done'
        }
      },
      Status: {
        select: { name: '6. Done' }
      }
    }
  })
}

async function getPagesToSync() {
  const response = await notion.databases.query({
    database_id: databaseId,
    filter: {
      and: [
        {
          property: 'Pipeline',
          status: {
            equals: "Done"
          }
        },
        {
          property: 'Status',
          select: {
            does_not_equal: "6. Done"
          }
        },
      ]
    },
    sorts: [
      {
        timestamp: 'last_edited_time',
        direction: 'descending'
      }
    ]
  })

  return response.results
}


const databaseId = "REDACTED_CHANGE_ME";

async function syncDoneStatuses() {
  const pagesToSync = await getPagesToSync()

  if (pagesToSync.length === 0) {
    console.log("Nothing to sync")
  } else {
    console.log(`Syncing ${pagesToSync.length} pages`)
  }

  for (let page of pagesToSync) {
    if (!isFullPage(page)) {
      continue
    }

    await setPageDone(page)

    await sleep(500)
  }
}


async function main() {
  const delay = 1000;

  (function loop() {
    setTimeout(() => {
      syncDoneStatuses()

      loop()
    }, delay)
  })()
}


main()