Merge pull request #1140 from automatisch/notion-app
feat(notion): add auth and new DB items trigger
This commit is contained in:
7
packages/backend/src/apps/notion/assets/favicon.svg
Normal file
7
packages/backend/src/apps/notion/assets/favicon.svg
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="256px" height="268px" viewBox="0 0 256 268" version="1.1" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid">
|
||||||
|
<g>
|
||||||
|
<path d="M16.0924984,11.5384656 L164.089991,0.608048392 C182.268719,-0.952166138 186.940447,0.0998642306 198.370133,8.40912104 L245.613429,41.6907258 C253.405586,47.4144843 256,48.9746988 256,55.2066414 L256,237.73391 C256,249.172512 251.845372,255.939385 237.304172,256.973584 L65.4398551,267.377986 C54.5272689,267.895086 49.3295257,266.334872 43.6146827,259.050899 L8.82635648,213.813593 C2.58549836,205.486505 0,199.254562 0,191.970589 L0,29.7261093 C0,20.3737376 4.1546284,12.572665 16.0924984,11.5384656 Z" fill="#FFFFFF"></path>
|
||||||
|
<path d="M164.089991,0.608048392 L16.0924984,11.5384656 C4.1546284,12.572665 0,20.3737376 0,29.7261093 L0,191.970589 C0,199.254562 2.58549836,205.486505 8.82635648,213.813593 L43.6146827,259.050899 C49.3295257,266.334872 54.5272689,267.895086 65.4398551,267.377986 L237.304172,256.973584 C251.836456,255.939385 256,249.172512 256,237.73391 L256,55.2066414 C256,49.2956572 253.664136,47.5927945 246.790277,42.5466149 C246.394749,42.2616979 245.999494,41.9764014 245.604513,41.6907258 L198.370133,8.40912104 C186.940447,0.0998642306 182.268719,-0.952166138 164.089991,0.608048392 Z M69.3270182,52.219945 C55.2940029,53.1649893 52.1111653,53.3789615 44.1406979,46.8973846 L23.8757401,30.7781396 C21.8162569,28.6919099 22.8504562,26.0885805 28.039284,25.5714809 L170.313018,15.1759943 C182.259804,14.1328795 188.482831,18.2964234 193.154559,21.9339521 L217.556314,39.6134116 C218.599429,40.1394268 221.193843,43.2509404 218.073414,43.2509404 L71.1457825,52.0951279 L69.3270182,52.219945 Z M52.9670544,236.173696 L52.9670544,81.2221043 C52.9670544,74.455231 55.0443686,71.3348019 61.2673957,70.8087867 L230.020199,60.9303999 C235.743958,60.4133002 238.329456,64.0508289 238.329456,70.8087867 L238.329456,224.726179 C238.329456,231.493052 237.286341,237.216811 227.942885,237.73391 L66.4562234,247.095198 C57.1127673,247.612297 52.9670544,244.500784 52.9670544,236.173696 Z M212.376402,89.5313611 C213.410601,94.2120046 212.376402,98.8926482 207.695758,99.4275789 L199.912517,100.969962 L199.912517,215.373807 C193.154559,219.011336 186.931532,221.08865 181.733788,221.08865 C173.424532,221.08865 171.347217,218.485321 165.12419,210.693164 L114.225535,130.614039 L114.225535,208.089834 L130.326949,211.736279 C130.326949,211.736279 130.326949,221.097566 117.337048,221.097566 L81.523438,223.17488 C80.4803232,221.08865 81.523438,215.890907 85.1520513,214.856708 L94.5044229,212.262294 L94.5044229,109.823065 L81.523438,108.771035 C80.4803232,104.090391 83.0747371,97.3324337 90.3497945,96.8064185 L128.77565,94.2209202 L181.733788,175.334245 L181.733788,103.573292 L168.235704,102.021993 C167.192589,96.2893189 171.347217,92.1257749 176.536045,91.6175908 L212.376402,89.5313611 L212.376402,89.5313611 Z" fill="#000000"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
21
packages/backend/src/apps/notion/auth/generate-auth-url.ts
Normal file
21
packages/backend/src/apps/notion/auth/generate-auth-url.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { IField, IGlobalVariable } from '@automatisch/types';
|
||||||
|
import { URL, URLSearchParams } from 'url';
|
||||||
|
|
||||||
|
export default async function generateAuthUrl($: IGlobalVariable) {
|
||||||
|
const oauthRedirectUrlField = $.app.auth.fields.find(
|
||||||
|
(field: IField) => field.key == 'oAuthRedirectUrl'
|
||||||
|
);
|
||||||
|
const redirectUri = oauthRedirectUrlField.value as string;
|
||||||
|
const searchParams = new URLSearchParams({
|
||||||
|
client_id: $.auth.data.clientId as string,
|
||||||
|
redirect_uri: redirectUri,
|
||||||
|
response_type: 'code',
|
||||||
|
owner: 'user',
|
||||||
|
});
|
||||||
|
|
||||||
|
const url = new URL(`/v1/oauth/authorize?${searchParams}`, $.app.apiBaseUrl).toString();
|
||||||
|
|
||||||
|
await $.auth.set({
|
||||||
|
url,
|
||||||
|
});
|
||||||
|
}
|
49
packages/backend/src/apps/notion/auth/index.ts
Normal file
49
packages/backend/src/apps/notion/auth/index.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import generateAuthUrl from './generate-auth-url';
|
||||||
|
import verifyCredentials from './verify-credentials';
|
||||||
|
import isStillVerified from './is-still-verified';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'oAuthRedirectUrl',
|
||||||
|
label: 'OAuth Redirect URL',
|
||||||
|
type: 'string' as const,
|
||||||
|
required: true,
|
||||||
|
readOnly: true,
|
||||||
|
value: '{WEB_APP_URL}/app/notion/connections/add',
|
||||||
|
placeholder: null,
|
||||||
|
description:
|
||||||
|
'When asked to input an OAuth callback or redirect URL in Notion OAuth, enter the URL above.',
|
||||||
|
docUrl: 'https://automatisch.io/docs/notion#oauth-redirect-url',
|
||||||
|
clickToCopy: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'clientId',
|
||||||
|
label: 'Client ID',
|
||||||
|
type: 'string' as const,
|
||||||
|
required: true,
|
||||||
|
readOnly: false,
|
||||||
|
value: null,
|
||||||
|
placeholder: null,
|
||||||
|
description: null,
|
||||||
|
docUrl: 'https://automatisch.io/docs/notion#client-id',
|
||||||
|
clickToCopy: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'clientSecret',
|
||||||
|
label: 'Client Secret',
|
||||||
|
type: 'string' as const,
|
||||||
|
required: true,
|
||||||
|
readOnly: false,
|
||||||
|
value: null,
|
||||||
|
placeholder: null,
|
||||||
|
description: null,
|
||||||
|
docUrl: 'https://automatisch.io/docs/notion#client-secret',
|
||||||
|
clickToCopy: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
generateAuthUrl,
|
||||||
|
verifyCredentials,
|
||||||
|
isStillVerified,
|
||||||
|
};
|
@@ -0,0 +1,9 @@
|
|||||||
|
import { IGlobalVariable } from '@automatisch/types';
|
||||||
|
import getCurrentUser from '../common/get-current-user';
|
||||||
|
|
||||||
|
const isStillVerified = async ($: IGlobalVariable) => {
|
||||||
|
const user = await getCurrentUser($);
|
||||||
|
return !!user.id;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default isStillVerified;
|
53
packages/backend/src/apps/notion/auth/verify-credentials.ts
Normal file
53
packages/backend/src/apps/notion/auth/verify-credentials.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { IGlobalVariable, IField } from '@automatisch/types';
|
||||||
|
import getCurrentUser from '../common/get-current-user';
|
||||||
|
|
||||||
|
const verifyCredentials = async ($: IGlobalVariable) => {
|
||||||
|
const oauthRedirectUrlField = $.app.auth.fields.find(
|
||||||
|
(field: IField) => field.key == 'oAuthRedirectUrl'
|
||||||
|
);
|
||||||
|
const redirectUri = oauthRedirectUrlField.value as string;
|
||||||
|
const response = await $.http.post(
|
||||||
|
`${$.app.apiBaseUrl}/v1/oauth/token`,
|
||||||
|
{
|
||||||
|
redirect_uri: redirectUri,
|
||||||
|
code: $.auth.data.code,
|
||||||
|
grant_type: 'authorization_code',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Basic ${Buffer.from(
|
||||||
|
$.auth.data.clientId + ':' + $.auth.data.clientSecret
|
||||||
|
).toString('base64')}`,
|
||||||
|
},
|
||||||
|
additionalProperties: {
|
||||||
|
skipAddingAuthHeader: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
$.auth.data.accessToken = data.access_token;
|
||||||
|
|
||||||
|
await $.auth.set({
|
||||||
|
clientId: $.auth.data.clientId,
|
||||||
|
clientSecret: $.auth.data.clientSecret,
|
||||||
|
accessToken: data.access_token,
|
||||||
|
botId: data.bot_id,
|
||||||
|
duplicatedTemplateId: data.duplicated_template_id,
|
||||||
|
owner: data.owner,
|
||||||
|
tokenType: data.token_type,
|
||||||
|
workspaceIcon: data.workspace_icon,
|
||||||
|
workspaceId: data.workspace_id,
|
||||||
|
workspaceName: data.workspace_name,
|
||||||
|
screenName: data.workspace_name,
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentUser = await getCurrentUser($);
|
||||||
|
|
||||||
|
await $.auth.set({
|
||||||
|
screenName: `${currentUser.name} @ ${data.workspace_name}`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default verifyCredentials;
|
14
packages/backend/src/apps/notion/common/add-auth-header.ts
Normal file
14
packages/backend/src/apps/notion/common/add-auth-header.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { TBeforeRequest } from '@automatisch/types';
|
||||||
|
|
||||||
|
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
||||||
|
if (requestConfig.additionalProperties?.skipAddingAuthHeader) return requestConfig;
|
||||||
|
|
||||||
|
if ($.auth.data?.accessToken) {
|
||||||
|
const authorizationHeader = `Bearer ${$.auth.data.accessToken}`;
|
||||||
|
requestConfig.headers.Authorization = authorizationHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default addAuthHeader;
|
@@ -0,0 +1,9 @@
|
|||||||
|
import { TBeforeRequest } from '@automatisch/types';
|
||||||
|
|
||||||
|
const addNotionVersionHeader: TBeforeRequest = ($, requestConfig) => {
|
||||||
|
requestConfig.headers['Notion-Version'] = '2022-06-28';
|
||||||
|
|
||||||
|
return requestConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default addNotionVersionHeader;
|
17
packages/backend/src/apps/notion/common/get-current-user.ts
Normal file
17
packages/backend/src/apps/notion/common/get-current-user.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||||
|
|
||||||
|
type Owner = {
|
||||||
|
user: {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCurrentUser = async ($: IGlobalVariable): Promise<IJSONObject> => {
|
||||||
|
const userId = ($.auth.data.owner as Owner).user.id;
|
||||||
|
const response = await $.http.get(`/v1/users/${userId}`);
|
||||||
|
|
||||||
|
const currentUser = response.data;
|
||||||
|
return currentUser;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getCurrentUser;
|
3
packages/backend/src/apps/notion/dynamic-data/index.ts
Normal file
3
packages/backend/src/apps/notion/dynamic-data/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import listDatabases from './list-databases';
|
||||||
|
|
||||||
|
export default [listDatabases];
|
@@ -0,0 +1,60 @@
|
|||||||
|
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||||
|
|
||||||
|
type Database = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
title: [
|
||||||
|
{
|
||||||
|
plain_text: string;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseData = {
|
||||||
|
results: Database[];
|
||||||
|
next_cursor?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Payload = {
|
||||||
|
filter: {
|
||||||
|
value: 'database';
|
||||||
|
property: 'object';
|
||||||
|
};
|
||||||
|
start_cursor?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'List databases',
|
||||||
|
key: 'listDatabases',
|
||||||
|
|
||||||
|
async run($: IGlobalVariable) {
|
||||||
|
const databases: {
|
||||||
|
data: IJSONObject[];
|
||||||
|
error: IJSONObject | null;
|
||||||
|
} = {
|
||||||
|
data: [],
|
||||||
|
error: null,
|
||||||
|
};
|
||||||
|
const payload: Payload = {
|
||||||
|
filter: {
|
||||||
|
value: 'database',
|
||||||
|
property: 'object'
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
do {
|
||||||
|
const response = await $.http.post<ResponseData>('/v1/search', payload);
|
||||||
|
|
||||||
|
payload.start_cursor = response.data.next_cursor;
|
||||||
|
|
||||||
|
for (const database of response.data.results) {
|
||||||
|
databases.data.push({
|
||||||
|
value: database.id as string,
|
||||||
|
name: database.title[0].plain_text as string,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} while (payload.start_cursor);
|
||||||
|
|
||||||
|
return databases;
|
||||||
|
},
|
||||||
|
};
|
0
packages/backend/src/apps/notion/index.d.ts
vendored
Normal file
0
packages/backend/src/apps/notion/index.d.ts
vendored
Normal file
24
packages/backend/src/apps/notion/index.ts
Normal file
24
packages/backend/src/apps/notion/index.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import defineApp from '../../helpers/define-app';
|
||||||
|
import addAuthHeader from './common/add-auth-header';
|
||||||
|
import addNotionVersionHeader from './common/add-notion-version-header';
|
||||||
|
import auth from './auth';
|
||||||
|
import triggers from './triggers';
|
||||||
|
import dynamicData from './dynamic-data';
|
||||||
|
|
||||||
|
export default defineApp({
|
||||||
|
name: 'Notion',
|
||||||
|
key: 'notion',
|
||||||
|
baseUrl: 'https://notion.com',
|
||||||
|
apiBaseUrl: 'https://api.notion.com',
|
||||||
|
iconUrl: '{BASE_URL}/apps/notion/assets/favicon.svg',
|
||||||
|
authDocUrl: 'https://automatisch.io/docs/apps/notion/connection',
|
||||||
|
primaryColor: '000000',
|
||||||
|
supportsConnections: true,
|
||||||
|
beforeRequest: [
|
||||||
|
addAuthHeader,
|
||||||
|
addNotionVersionHeader,
|
||||||
|
],
|
||||||
|
auth,
|
||||||
|
triggers,
|
||||||
|
dynamicData,
|
||||||
|
});
|
3
packages/backend/src/apps/notion/triggers/index.ts
Normal file
3
packages/backend/src/apps/notion/triggers/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import newDatabaseItems from './new-database-items';
|
||||||
|
|
||||||
|
export default [newDatabaseItems];
|
@@ -0,0 +1,32 @@
|
|||||||
|
import defineTrigger from '../../../../helpers/define-trigger';
|
||||||
|
import newDatabaseItems from './new-database-items';
|
||||||
|
|
||||||
|
export default defineTrigger({
|
||||||
|
name: 'New database items',
|
||||||
|
key: 'newDatabaseItems',
|
||||||
|
pollInterval: 15,
|
||||||
|
description: 'Triggers when a new database item is created',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
label: 'Database',
|
||||||
|
key: 'databaseId',
|
||||||
|
type: 'dropdown' as const,
|
||||||
|
required: false,
|
||||||
|
variables: false,
|
||||||
|
source: {
|
||||||
|
type: 'query',
|
||||||
|
name: 'getDynamicData',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
name: 'key',
|
||||||
|
value: 'listDatabases',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run($) {
|
||||||
|
await newDatabaseItems($);
|
||||||
|
},
|
||||||
|
});
|
@@ -0,0 +1,50 @@
|
|||||||
|
import { IGlobalVariable } from '@automatisch/types';
|
||||||
|
|
||||||
|
type DatabaseItem = {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseData = {
|
||||||
|
results: DatabaseItem[];
|
||||||
|
next_cursor?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Payload = {
|
||||||
|
sorts: [
|
||||||
|
{
|
||||||
|
timestamp: 'created_time' | 'last_edited_time';
|
||||||
|
direction: 'ascending' | 'descending';
|
||||||
|
}
|
||||||
|
];
|
||||||
|
start_cursor?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const newDatabaseItems = async ($: IGlobalVariable) => {
|
||||||
|
const payload: Payload = {
|
||||||
|
sorts: [
|
||||||
|
{
|
||||||
|
timestamp: 'created_time',
|
||||||
|
direction: 'descending'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const databaseId = $.step.parameters.databaseId as string;
|
||||||
|
const path = `/v1/databases/${databaseId}/query`;
|
||||||
|
do {
|
||||||
|
const response = await $.http.post<ResponseData>(path, payload);
|
||||||
|
|
||||||
|
payload.start_cursor = response.data.next_cursor;
|
||||||
|
|
||||||
|
for (const databaseItem of response.data.results) {
|
||||||
|
$.pushTriggerItem({
|
||||||
|
raw: databaseItem,
|
||||||
|
meta: {
|
||||||
|
internalId: databaseItem.id,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} while (payload.start_cursor);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default newDatabaseItems;
|
@@ -44,9 +44,12 @@ const getDynamicData = async (
|
|||||||
$.step.parameters[parameterKey] = parameterValue;
|
$.step.parameters[parameterKey] = parameterValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const priorExecutionSteps = await ExecutionStep.query().where({
|
const lastExecution = await flow.$relatedQuery('lastExecution');
|
||||||
execution_id: (await flow.$relatedQuery('lastExecution')).id,
|
const lastExecutionId = lastExecution?.id;
|
||||||
});
|
|
||||||
|
const priorExecutionSteps = lastExecutionId ? await ExecutionStep.query().where({
|
||||||
|
execution_id: lastExecutionId,
|
||||||
|
}) : [];
|
||||||
|
|
||||||
// compute variables in parameters
|
// compute variables in parameters
|
||||||
const computedParameters = computeParameters($.step.parameters, priorExecutionSteps);
|
const computedParameters = computeParameters($.step.parameters, priorExecutionSteps);
|
||||||
|
@@ -142,6 +142,15 @@ export default defineConfig({
|
|||||||
{ text: 'Connection', link: '/apps/http-request/connection' },
|
{ text: 'Connection', link: '/apps/http-request/connection' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: 'Notion',
|
||||||
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{ text: 'Triggers', link: '/apps/notion/triggers' },
|
||||||
|
{ text: 'Connection', link: '/apps/notion/connection' },
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: 'Ntfy',
|
text: 'Ntfy',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
22
packages/docs/pages/apps/notion/connection.md
Normal file
22
packages/docs/pages/apps/notion/connection.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Notion
|
||||||
|
|
||||||
|
:::info
|
||||||
|
This page explains the steps you need to follow to set up the Notion
|
||||||
|
connection in Automatisch. If any of the steps are outdated, please let us know!
|
||||||
|
:::
|
||||||
|
|
||||||
|
1. Go to the [link](https://www.notion.so/my-integrations) to **create an
|
||||||
|
integration** on Notion API.
|
||||||
|
1. Fill out the Name field.
|
||||||
|
1. Click on the **Submit** button.
|
||||||
|
1. Go to the **Capabilities** page via the sidebar.
|
||||||
|
1. Select the **Read user information without email addresses** option under the **User Capabilities** section and then save the changes.
|
||||||
|
1. Go to the **Distribution** page via the sidebar.
|
||||||
|
1. Make the integration public by enabling the checkbox.
|
||||||
|
1. Fill out the necessary fields under the **Organization Information** section.
|
||||||
|
1. Copy **OAuth Redirect URL** from Automatisch and paste it to the **Redirect URIs** field.
|
||||||
|
1. Click on the **Submit** button.
|
||||||
|
1. Accept making the integration public by clicking on the **Continue** button in the dialog.
|
||||||
|
1. Copy **OAuth client ID** and **OAuth client secret** values and paste them into Automatisch as **Client ID** and **Client Secret**, respectively.
|
||||||
|
1. Click **Submit** button on Automatisch.
|
||||||
|
1. Now, you can start using the Notion connection with Automatisch.
|
12
packages/docs/pages/apps/notion/triggers.md
Normal file
12
packages/docs/pages/apps/notion/triggers.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
favicon: /favicons/notion.svg
|
||||||
|
items:
|
||||||
|
- name: New database items
|
||||||
|
desc: Triggers when a new database item is created.
|
||||||
|
---
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import CustomListing from '../../components/CustomListing.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CustomListing />
|
@@ -18,6 +18,7 @@ Following integrations are currently supported by Automatisch.
|
|||||||
- [Google Forms](/apps/google-forms/triggers)
|
- [Google Forms](/apps/google-forms/triggers)
|
||||||
- [Google Sheets](/apps/google-sheets/triggers)
|
- [Google Sheets](/apps/google-sheets/triggers)
|
||||||
- [HTTP Request](/apps/http-request/actions)
|
- [HTTP Request](/apps/http-request/actions)
|
||||||
|
- [Notion](/apps/notion/triggers)
|
||||||
- [Ntfy](/apps/ntfy/actions)
|
- [Ntfy](/apps/ntfy/actions)
|
||||||
- [OpenAI](/apps/openai/actions)
|
- [OpenAI](/apps/openai/actions)
|
||||||
- [PostgreSQL](/apps/postgresql/actions)
|
- [PostgreSQL](/apps/postgresql/actions)
|
||||||
|
7
packages/docs/pages/public/favicons/notion.svg
Normal file
7
packages/docs/pages/public/favicons/notion.svg
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="256px" height="268px" viewBox="0 0 256 268" version="1.1" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid">
|
||||||
|
<g>
|
||||||
|
<path d="M16.0924984,11.5384656 L164.089991,0.608048392 C182.268719,-0.952166138 186.940447,0.0998642306 198.370133,8.40912104 L245.613429,41.6907258 C253.405586,47.4144843 256,48.9746988 256,55.2066414 L256,237.73391 C256,249.172512 251.845372,255.939385 237.304172,256.973584 L65.4398551,267.377986 C54.5272689,267.895086 49.3295257,266.334872 43.6146827,259.050899 L8.82635648,213.813593 C2.58549836,205.486505 0,199.254562 0,191.970589 L0,29.7261093 C0,20.3737376 4.1546284,12.572665 16.0924984,11.5384656 Z" fill="#FFFFFF"></path>
|
||||||
|
<path d="M164.089991,0.608048392 L16.0924984,11.5384656 C4.1546284,12.572665 0,20.3737376 0,29.7261093 L0,191.970589 C0,199.254562 2.58549836,205.486505 8.82635648,213.813593 L43.6146827,259.050899 C49.3295257,266.334872 54.5272689,267.895086 65.4398551,267.377986 L237.304172,256.973584 C251.836456,255.939385 256,249.172512 256,237.73391 L256,55.2066414 C256,49.2956572 253.664136,47.5927945 246.790277,42.5466149 C246.394749,42.2616979 245.999494,41.9764014 245.604513,41.6907258 L198.370133,8.40912104 C186.940447,0.0998642306 182.268719,-0.952166138 164.089991,0.608048392 Z M69.3270182,52.219945 C55.2940029,53.1649893 52.1111653,53.3789615 44.1406979,46.8973846 L23.8757401,30.7781396 C21.8162569,28.6919099 22.8504562,26.0885805 28.039284,25.5714809 L170.313018,15.1759943 C182.259804,14.1328795 188.482831,18.2964234 193.154559,21.9339521 L217.556314,39.6134116 C218.599429,40.1394268 221.193843,43.2509404 218.073414,43.2509404 L71.1457825,52.0951279 L69.3270182,52.219945 Z M52.9670544,236.173696 L52.9670544,81.2221043 C52.9670544,74.455231 55.0443686,71.3348019 61.2673957,70.8087867 L230.020199,60.9303999 C235.743958,60.4133002 238.329456,64.0508289 238.329456,70.8087867 L238.329456,224.726179 C238.329456,231.493052 237.286341,237.216811 227.942885,237.73391 L66.4562234,247.095198 C57.1127673,247.612297 52.9670544,244.500784 52.9670544,236.173696 Z M212.376402,89.5313611 C213.410601,94.2120046 212.376402,98.8926482 207.695758,99.4275789 L199.912517,100.969962 L199.912517,215.373807 C193.154559,219.011336 186.931532,221.08865 181.733788,221.08865 C173.424532,221.08865 171.347217,218.485321 165.12419,210.693164 L114.225535,130.614039 L114.225535,208.089834 L130.326949,211.736279 C130.326949,211.736279 130.326949,221.097566 117.337048,221.097566 L81.523438,223.17488 C80.4803232,221.08865 81.523438,215.890907 85.1520513,214.856708 L94.5044229,212.262294 L94.5044229,109.823065 L81.523438,108.771035 C80.4803232,104.090391 83.0747371,97.3324337 90.3497945,96.8064185 L128.77565,94.2209202 L181.733788,175.334245 L181.733788,103.573292 L168.235704,102.021993 C167.192589,96.2893189 171.347217,92.1257749 176.536045,91.6175908 L212.376402,89.5313611 L212.376402,89.5313611 Z" fill="#000000"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
Reference in New Issue
Block a user