Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/dragonman225/trigger-webhook-from-notion
Add a button that can trigger a POST webhook in Notion.so's table.
https://github.com/dragonman225/trigger-webhook-from-notion
notablog notion
Last synced: 8 days ago
JSON representation
Add a button that can trigger a POST webhook in Notion.so's table.
- Host: GitHub
- URL: https://github.com/dragonman225/trigger-webhook-from-notion
- Owner: dragonman225
- License: mit
- Created: 2019-08-13T16:18:04.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2022-05-31T21:15:21.000Z (over 2 years ago)
- Last Synced: 2024-10-13T12:05:21.443Z (23 days ago)
- Topics: notablog, notion
- Language: JavaScript
- Size: 918 KB
- Stars: 73
- Watchers: 3
- Forks: 2
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Trigger Webhook from Notion
Trigger a webhook that activates on a POST request directly from a [Notion table](https://www.notion.so/b6fcf809ca5047b89f423948dce013a0?v=03ddc4d6130a47f8b68e74c9d0061de2).
Below is a demo where I can just click a button on a Notion table and trigger [Netlify](https://www.netlify.com)'s build webhook to update my blog built with [Notablog](https://github.com/dragonman225/notablog).
![demo-gif](assets/demo.gif)
## How to Use
This is a **proof-of-concept**, so it requires a few changes in code to adapt to your need. They are simple, and I'll explain as clear as possible.
1. Open `src/extension.js`, replace the dummy `buildHookUrl` with your webhook URL.
Any webhook should work, as long as the webhook can be triggered by an empty `POST` request (for example, Netlify's).
```javascript
const buildHookUrl = 'https://Replace.this.string.with.your.webhook.URL'
```2. (Optional) If you want the trigger button appear only on one table, open `manifest.json`, in `content_scripts.matches`, change `https://www.notion.so/*` to a table's URL.
If you skip this step, you will see the trigger button **on every table**.
```javascript
"content_scripts": [
{
"matches": [
"https://www.notion.so/*" // Change this
],
// ...
}
]
```3. Load this extension into your browser. Since this is an unpacked extension, it needs to be loaded in developer mode or debug mode.
For **Google Chrome** or **Chromium-based**, follow the tutorial: https://developer.chrome.com/extensions/getstarted.
For **Firefox**, follow the tutorial: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_first_WebExtension#Installing.4. Open a table in Notion to test it out!
## How it works
### Motivation
In my case, I want to trigger Netlify's webhook to rebuild my static blog when I update posts on Notion with a single click. The webhook needs to be triggered by an empty `POST` request, but I couldn't find a block in Notion that can do a `POST` request. In addition, I use a full-page table to manage my posts, so there's actually no way to insert other type of blocks unless I change the [Notablog](https://github.com/dragonman225/notablog)'s logic.
### The Extension
#### Prepare a trigger button
I think of HTML's ``, where I can specify the HTTP method and in my case I just need to `POST` with an empty form. This is attractive to me because it doesn't need AJAX, which means easier to implement !
So, I write the following
```javascript
/** Prepare a button */
const button = document.createElement('DIV')
/** Give the button an id so we can check if it exists later */
button.setAttribute('id', BUTTON_ID)
button.setAttribute('style', 'margin-left: 10px; display: inline-flex')
/**
* Use a dummy iframe to prevent redirect
* @see https://stackoverflow.com/a/28060195
*/
button.innerHTML = `\Trigger Site Update
`
```Create a `
`, inside the `` we have a ``, then we have a `` in the ``. The `` has `action` attribute set to the `buildHookUrl`, which is the webhook URL, and `method` attribute set to `post`.This translates to: When we click the button, an empty form will be submit to the URL in `action` with `post` method. This is exactly what I want.
---
Wait! What's the `` doing there?
Actually, the script works without the ``, but in that case after we click the button, we will be redirected to the webhook URL. This behavior is a bit annoying, so I find a way to prevent it, see https://stackoverflow.com/a/28060195.
The `` is not rendered, and the I set `target` attribute of `` to the ``'s `id`, so the redirect happens in the ``, without effecting the main page.
#### Inject the button to the page
By default, the browser loads content scripts of an extension after a page is **loaded**. The "**loaded**" means HTML is loaded. This is OK for static web pages, but since Notion is an React app, the parent element we want to inject to **may not exist** when HTML is loaded, so we need additional techniques to handle it.
In the past, I used to use `DOMSubtreeModified` event to trigger my injection logic ([like this](https://github.com/dragonman225/AlbumArtTool/blob/dcac7a5e58838e80a279f710f7ac8e89da34c7b5/src/extension.js#L186)), but now this event seems to be completely removed from Firefox 68, so I have to find something new, which is the [`MutationObserver`](https://developer.mozilla.org/zh-TW/docs/Web/API/MutationObserver).
```javascript
/**
* Use MutationObserver API, DOMSubtreeModified event is deprecated.
* @see https://developer.mozilla.org/zh-TW/docs/Web/API/MutationObserver
*/
const observer = new MutationObserver(function (mutations) {
/** Try to hook up the button if not exist */
let toolbar = document.querySelector('div.notion-scroller:nth-child(2) > div:nth-child(2) > div:nth-child(1) > div:nth-child(1) > div:nth-child(2)')
let btn = document.getElementById(BUTTON_ID)
/** btn doesn't exists && toolbar exists */
if (!btn && toolbar) toolbar.appendChild(button)
});
const observerConfig = {
attributes: true,
childList: true,
characterData: true,
subtree: true
}
observer.observe(document, observerConfig)
```The `MutationObserver` behaves the same as `DOMSubtreeModified` event, if I set `subtree: true` in the config object.
Note that here I target `document` in `observe()`, which seems to be inefficient. But since Notion's React app is bundled as an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE), which does not expose any variable that can be accessed from outside bundle, also we don't know how does the app execute. So listening to all mutations in `document` makes sure we don't lose any chance to detect if the page is ready for injection.