feat(Notion (Beta) Node): Use resource locator component for database and page parameters (#4340)

* use resource locator component for database -> get (Notion V1/V2)

* getDatabases search function for V1/V2 with url

* updated database get list placeholder

* get database RLC by url - regex support optional workspace domain names

* fixed linting error

* listSearch getDatabases support filter query

* support extractValue in getCurrentNodeParameter for RLC

* RLC for database page create/getAll operation

* RLC for database get operation support "By ID" with optional v param.

* use RLC in append blocks operation

* use RLC in NotionTrigger.nodes.ts

* removed unused loadOptions getDatabases

* support database RLC in createPage/createDbPage operation

* page create operation use RLC for parent page param

* page archive operation use RLC for page param

* removed unused imports

* fixed missing extractPageId in NotionV1.node.ts

* database page get operation use RLC for page param

* database page update operation use RLC for page param

* block getAll children operation use RLC for page param

* block append operation use RLC for block param

* support databaseId with optional '-' characters

* support blockId with optional '-' characters

* support pageId with optional '-' characters

* improved RLC descriptions and hints

* NotionTrigger node support databseId with optional '-' characters

* stricter RLC by ID regex rules for uuids

* stricter RLC by URL regex rules for uuids

* stricter RLC by ID regex rules for uuids (support max length)

* RLC regex from URL allow both http and https

* RLC by ID only allow uuid v4 with optional dash

* removed RLC from URL hint "Use Notion's copy link..."

* RLC from URL only allow uuid v4

* DB Status Column: Support Simplify Properties

* Notion Credentials: Support custom Notion-Version header

Use latest Notion-Version 2022-02-22 if not set

* DB Status Column: Support DB Page Create/Update

* DB Status Column: Support DB Page GetMany Filters

* removed unused paginationToken args

* Database Get: RLC by URL improve validation error message
This commit is contained in:
Marcus 2022-11-11 13:37:52 +01:00 committed by GitHub
parent c7133ecd3f
commit 277b6b73c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 775 additions and 202 deletions

View file

@ -2674,6 +2674,7 @@ export function getLoadOptionsFunctions(
}, },
getCurrentNodeParameter: ( getCurrentNodeParameter: (
parameterPath: string, parameterPath: string,
options?: IGetNodeParameterOptions,
): NodeParameterValueType | object | undefined => { ): NodeParameterValueType | object | undefined => {
const nodeParameters = additionalData.currentNodeParameters; const nodeParameters = additionalData.currentNodeParameters;
@ -2681,7 +2682,25 @@ export function getLoadOptionsFunctions(
parameterPath = `${path.split('.').slice(1, -1).join('.')}.${parameterPath.slice(1)}`; parameterPath = `${path.split('.').slice(1, -1).join('.')}.${parameterPath.slice(1)}`;
} }
return get(nodeParameters, parameterPath); let returnData = get(nodeParameters, parameterPath);
// This is outside the try/catch because it throws errors with proper messages
if (options?.extractValue) {
const nodeType = workflow.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
if (nodeType === undefined) {
throw new Error(
`Node type "${node.type}" is not known so can not return parameter value!`,
);
}
returnData = extractValue(
returnData,
parameterPath,
node,
nodeType,
) as NodeParameterValueType;
}
return returnData;
}, },
getCurrentNodeParameters: (): INodeParameters | undefined => { getCurrentNodeParameters: (): INodeParameters | undefined => {
return additionalData.currentNodeParameters; return additionalData.currentNodeParameters;

View file

@ -37,38 +37,122 @@ export const blockFields: INodeProperties[] = [
/* block:append */ /* block:append */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Block ID or Link', displayName: 'Block',
name: 'blockId', name: 'blockId',
type: 'string', type: 'resourceLocator',
default: '', default: { mode: 'url', value: '' },
required: true, required: true,
modes: [
{
displayName: 'Link',
name: 'url',
type: 'string',
placeholder:
'https://www.notion.so/My-Page-b4eeb113e118403ba450af65ac25f0b9',
validation: [
{
type: 'regex',
properties: {
regex:
'(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*',
errorMessage: 'Not a valid Notion Block URL',
},
},
],
extractValue: {
type: 'regex',
regex: '(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})',
},
},
{
displayName: 'ID',
name: 'id',
type: 'string',
placeholder: 'ab1545b247fb49fa92d6f4b49f4d8116',
validation: [
{
type: 'regex',
properties: {
regex: '^(([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})|([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}))[ \t]*',
errorMessage: 'Not a valid Notion Block ID',
},
},
],
extractValue: {
type: 'regex',
regex: '^([0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12})',
},
url: '=https://www.notion.so/{{$value.replace(/-/g, "")}}',
},
],
displayOptions: { displayOptions: {
show: { show: {
resource: ['block'], resource: ['block'],
operation: ['append'], operation: ['append'],
}, },
}, },
description: description: "The Notion Block to append blocks to",
"The Block URL from Notion's 'copy link' functionality (or just the ID contained within the URL). Pages are also blocks, so you can use a page URL/ID here too.",
}, },
...blocks('block', 'append'), ...blocks('block', 'append'),
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* block:getAll */ /* block:getAll */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Block ID or Link', displayName: 'Block',
name: 'blockId', name: 'blockId',
type: 'string', type: 'resourceLocator',
default: '', default: { mode: 'url', value: '' },
required: true, required: true,
modes: [
{
displayName: 'Link',
name: 'url',
type: 'string',
placeholder:
'https://www.notion.so/My-Page-b4eeb113e118403ba450af65ac25f0b9',
validation: [
{
type: 'regex',
properties: {
regex:
'(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*',
errorMessage: 'Not a valid Notion Block URL',
},
},
],
extractValue: {
type: 'regex',
regex: '(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})',
},
},
{
displayName: 'ID',
name: 'id',
type: 'string',
placeholder: 'ab1545b247fb49fa92d6f4b49f4d8116',
validation: [
{
type: 'regex',
properties: {
regex: '^(([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})|([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}))[ \t]*',
errorMessage: 'Not a valid Notion Block ID',
},
},
],
extractValue: {
type: 'regex',
regex: '^([0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12})',
},
url: '=https://www.notion.so/{{$value.replace(/-/g, "")}}',
},
],
displayOptions: { displayOptions: {
show: { show: {
resource: ['block'], resource: ['block'],
operation: ['getAll'], operation: ['getAll'],
}, },
}, },
description: description: "The Notion Block to get all children from",
"The Block URL from Notion's 'copy link' functionality (or just the ID contained within the URL). Pages are also blocks, so you can use a page URL/ID here too.",
}, },
{ {
displayName: 'Return All', displayName: 'Return All',

View file

@ -196,20 +196,69 @@ const typeMention: INodeProperties[] = [
description: 'The ID of the page being mentioned', description: 'The ID of the page being mentioned',
}, },
{ {
displayName: 'Database Name or ID', displayName: 'Database',
name: 'database', name: 'database',
type: 'options', type: 'resourceLocator',
typeOptions: { default: { mode: 'list', value: '' },
loadOptionsMethod: 'getDatabases', modes: [
}, {
displayName: 'Database',
name: 'list',
type: 'list',
placeholder: 'Select a Database...',
typeOptions: {
searchListMethod: 'getDatabases',
searchable: true,
},
},
{
displayName: 'Link',
name: 'url',
type: 'string',
placeholder:
'https://www.notion.so/0fe2f7de558b471eab07e9d871cdf4a9?v=f2d424ba0c404733a3f500c78c881610',
validation: [
{
type: 'regex',
properties: {
regex:
'(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*',
errorMessage: 'Not a valid Notion Database URL',
},
},
],
extractValue: {
type: 'regex',
regex: '(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})',
},
},
{
displayName: 'ID',
name: 'id',
type: 'string',
placeholder: 'ab1545b247fb49fa92d6f4b49f4d8116',
validation: [
{
type: 'regex',
properties: {
regex: '^(([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})|([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}))[ \t]*',
errorMessage: 'Not a valid Notion Database ID',
},
},
],
extractValue: {
type: 'regex',
regex: '^([0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12})',
},
url: '=https://www.notion.so/{{$value.replace(/-/g, "")}}',
},
],
displayOptions: { displayOptions: {
show: { show: {
mentionType: ['database'], mentionType: ['database'],
}, },
}, },
default: '', description: "The Notion Database being mentioned",
description:
'The ID of the database being mentioned. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Range', displayName: 'Range',

View file

@ -67,20 +67,73 @@ export const databaseFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* database:get */ /* database:get */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Database Link or ID', displayName: 'Database',
name: 'databaseId', name: 'databaseId',
type: 'string', type: 'resourceLocator',
default: '', default: { mode: 'list', value: '' },
required: true, required: true,
modes: [
{
displayName: 'Database',
name: 'list',
type: 'list',
placeholder: 'Select a Database...',
typeOptions: {
searchListMethod: 'getDatabases',
searchable: true,
},
},
{
displayName: 'Link',
name: 'url',
type: 'string',
placeholder:
'https://www.notion.so/0fe2f7de558b471eab07e9d871cdf4a9?v=f2d424ba0c404733a3f500c78c881610',
validation: [
{
type: 'regex',
properties: {
regex:
'(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*',
errorMessage: 'Not a valid Notion Database URL. Hint: use the URL of the database itself, not a page containing it.',
},
},
],
extractValue: {
type: 'regex',
regex: '(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})',
},
},
{
displayName: 'ID',
name: 'id',
type: 'string',
placeholder: 'ab1545b247fb49fa92d6f4b49f4d8116',
validation: [
{
type: 'regex',
properties: {
regex: '^(([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})|([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}))[ \t]*',
errorMessage: 'Not a valid Notion Database ID',
},
},
],
extractValue: {
type: 'regex',
regex: '^([0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12})',
},
url: '=https://www.notion.so/{{$value.replace(/-/g, "")}}',
},
],
displayOptions: { displayOptions: {
show: { show: {
resource: ['database'], resource: ['database'],
operation: ['get'], operation: ['get'],
}, },
}, },
description: description: "The Notion Database to get",
"The Database URL from Notion's 'copy link' functionality (or just the ID contained within the URL)",
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* database:getAll */ /* database:getAll */

View file

@ -86,22 +86,71 @@ export const databasePageFields: INodeProperties[] = [
/* databasePage:create */ /* databasePage:create */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Database Name or ID', displayName: 'Database',
name: 'databaseId', name: 'databaseId',
type: 'options', type: 'resourceLocator',
default: '', default: { mode: 'list', value: '' },
typeOptions: {
loadOptionsMethod: 'getDatabases',
},
required: true, required: true,
modes: [
{
displayName: 'Database',
name: 'list',
type: 'list',
placeholder: 'Select a Database...',
typeOptions: {
searchListMethod: 'getDatabases',
searchable: true,
},
},
{
displayName: 'Link',
name: 'url',
type: 'string',
placeholder:
'https://www.notion.so/0fe2f7de558b471eab07e9d871cdf4a9?v=f2d424ba0c404733a3f500c78c881610',
validation: [
{
type: 'regex',
properties: {
regex:
'(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*',
errorMessage: 'Not a valid Notion Database URL',
},
},
],
extractValue: {
type: 'regex',
regex: '(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})',
},
},
{
displayName: 'ID',
name: 'id',
type: 'string',
placeholder: 'ab1545b247fb49fa92d6f4b49f4d8116',
validation: [
{
type: 'regex',
properties: {
regex: '^(([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})|([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}))[ \t]*',
errorMessage: 'Not a valid Notion Database ID',
},
},
],
extractValue: {
type: 'regex',
regex: '^([0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12})',
},
url: '=https://www.notion.so/{{$value.replace(/-/g, "")}}',
},
],
displayOptions: { displayOptions: {
show: { show: {
resource: ['databasePage'], resource: ['databasePage'],
operation: ['create'], operation: ['create'],
}, },
}, },
description: description: "The Notion Database to operate on",
"The Database Page URL from Notion's 'copy link' functionality (or just the ID contained within the URL). Choose from the list, or specify an ID using an <a href=\"https://docs.n8n.io/code-examples/expressions/\">expression</a>.",
}, },
{ {
displayName: 'Title', displayName: 'Title',
@ -252,6 +301,22 @@ export const databasePageFields: INodeProperties[] = [
description: description:
'Name of the option you want to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', 'Name of the option you want to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{
displayName: 'Status Name or ID',
name: 'statusValue',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getPropertySelectValues',
},
displayOptions: {
show: {
type: ['status'],
},
},
default: '',
description:
'Name of the option you want to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{ {
displayName: 'Email', displayName: 'Email',
name: 'emailValue', name: 'emailValue',
@ -471,19 +536,61 @@ export const databasePageFields: INodeProperties[] = [
/* databasePage:update */ /* databasePage:update */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Database Page Link or ID', displayName: 'Database Page',
name: 'pageId', name: 'pageId',
type: 'string', type: 'resourceLocator',
default: '', default: { mode: 'url', value: '' },
required: true, required: true,
modes: [
{
displayName: 'Link',
name: 'url',
type: 'string',
placeholder:
'https://www.notion.so/My-Database-Page-b4eeb113e118403ba450af65ac25f0b9',
validation: [
{
type: 'regex',
properties: {
regex:
'(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*',
errorMessage: 'Not a valid Notion Database Page URL',
},
},
],
extractValue: {
type: 'regex',
regex: '(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})',
},
},
{
displayName: 'ID',
name: 'id',
type: 'string',
placeholder: 'ab1545b247fb49fa92d6f4b49f4d8116',
validation: [
{
type: 'regex',
properties: {
regex: '^(([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})|([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}))[ \t]*',
errorMessage: 'Not a valid Notion Database Page ID',
},
},
],
extractValue: {
type: 'regex',
regex: '^([0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12})',
},
url: '=https://www.notion.so/{{$value.replace(/-/g, "")}}',
},
],
displayOptions: { displayOptions: {
show: { show: {
resource: ['databasePage'], resource: ['databasePage'],
operation: ['update'], operation: ['update'],
}, },
}, },
description: description: "The Notion Database Page to update",
"The Database Page URL from Notion's 'copy link' functionality (or just the ID contained within the URL)",
}, },
{ {
displayName: 'Simplify', displayName: 'Simplify',
@ -620,6 +727,22 @@ export const databasePageFields: INodeProperties[] = [
}, },
default: '', default: '',
}, },
{
displayName: 'Status Name or ID',
name: 'statusValue',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getDatabaseOptionsFromPage',
},
displayOptions: {
show: {
type: ['status'],
},
},
default: '',
description:
'Name of the option you want to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{ {
displayName: 'Email', displayName: 'Email',
name: 'emailValue', name: 'emailValue',
@ -837,11 +960,54 @@ export const databasePageFields: INodeProperties[] = [
/* databasePage:get */ /* databasePage:get */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Database Page Link or ID', displayName: 'Database Page',
name: 'pageId', name: 'pageId',
type: 'string', type: 'resourceLocator',
default: '', default: { mode: 'url', value: '' },
required: true, required: true,
modes: [
{
displayName: 'Link',
name: 'url',
type: 'string',
placeholder:
'https://www.notion.so/My-Database-Page-b4eeb113e118403ba450af65ac25f0b9',
validation: [
{
type: 'regex',
properties: {
regex:
'(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*',
errorMessage: 'Not a valid Notion Database Page URL',
},
},
],
extractValue: {
type: 'regex',
regex: '(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})',
},
},
{
displayName: 'ID',
name: 'id',
type: 'string',
placeholder: 'ab1545b247fb49fa92d6f4b49f4d8116',
validation: [
{
type: 'regex',
properties: {
regex: '^(([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})|([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}))[ \t]*',
errorMessage: 'Not a valid Notion Database Page ID',
},
},
],
extractValue: {
type: 'regex',
regex: '^([0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12})',
},
url: '=https://www.notion.so/{{$value.replace(/-/g, "")}}',
},
],
displayOptions: { displayOptions: {
show: { show: {
version: [2], version: [2],
@ -849,8 +1015,7 @@ export const databasePageFields: INodeProperties[] = [
operation: ['get'], operation: ['get'],
}, },
}, },
description: description: "The Notion Database Page to get",
"The Database Page URL from Notion's 'copy link' functionality (or just the ID contained within the URL)",
}, },
{ {
displayName: 'Simplify', displayName: 'Simplify',
@ -870,22 +1035,71 @@ export const databasePageFields: INodeProperties[] = [
/* databasePage:getAll */ /* databasePage:getAll */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Database Name or ID', displayName: 'Database',
name: 'databaseId', name: 'databaseId',
type: 'options', type: 'resourceLocator',
description: default: { mode: 'list', value: '' },
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getDatabases',
},
default: '',
required: true, required: true,
modes: [
{
displayName: 'Database',
name: 'list',
type: 'list',
placeholder: 'Select a Database...',
typeOptions: {
searchListMethod: 'getDatabases',
searchable: true,
},
},
{
displayName: 'Link',
name: 'url',
type: 'string',
placeholder:
'https://www.notion.so/0fe2f7de558b471eab07e9d871cdf4a9?v=f2d424ba0c404733a3f500c78c881610',
validation: [
{
type: 'regex',
properties: {
regex:
'(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*',
errorMessage: 'Not a valid Notion Database URL',
},
},
],
extractValue: {
type: 'regex',
regex: '(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})',
},
},
{
displayName: 'ID',
name: 'id',
type: 'string',
placeholder: 'ab1545b247fb49fa92d6f4b49f4d8116',
validation: [
{
type: 'regex',
properties: {
regex: '^(([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})|([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}))[ \t]*',
errorMessage: 'Not a valid Notion Database ID',
},
},
],
extractValue: {
type: 'regex',
regex: '^([0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12})',
},
url: '=https://www.notion.so/{{$value.replace(/-/g, "")}}',
},
],
displayOptions: { displayOptions: {
show: { show: {
resource: ['databasePage'], resource: ['databasePage'],
operation: ['getAll'], operation: ['getAll'],
}, },
}, },
description: "The Notion Database to operate on",
}, },
{ {
displayName: 'Return All', displayName: 'Return All',

View file

@ -100,6 +100,22 @@ export const filters = (conditions: any) => [
}, },
default: '', default: '',
}, },
{
displayName: 'Status Name or ID',
name: 'statusValue',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getPropertySelectValues',
},
displayOptions: {
show: {
type: ['status'],
},
},
default: '',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
},
{ {
displayName: 'Email', displayName: 'Email',
name: 'emailValue', name: 'emailValue',

View file

@ -337,6 +337,12 @@ function getPropertyKeyValue(value: any, type: string, timezone: string, version
select: version === 1 ? { id: value.selectValue } : { name: value.selectValue }, select: version === 1 ? { id: value.selectValue } : { name: value.selectValue },
}; };
break; break;
case 'status':
result = {
type: 'status',
status: { name: value.statusValue },
};
break;
case 'date': case 'date':
const format = getDateFormat(value.includeTime); const format = getDateFormat(value.includeTime);
const timezoneValue = value.timezone === 'default' ? timezone : value.timezone; const timezoneValue = value.timezone === 'default' ? timezone : value.timezone;
@ -542,6 +548,8 @@ function simplifyProperty(property: any) {
// tslint:disable-next-line: no-any // tslint:disable-next-line: no-any
(file: { type: string; [key: string]: any }) => file[file.type].url, (file: { type: string; [key: string]: any }) => file[file.type].url,
); );
} else if (['status'].includes(property.type)) {
result = property[type].name;
} }
return result; return result;
} }
@ -622,6 +630,7 @@ export function getConditions() {
checkbox: 'checkbox', checkbox: 'checkbox',
select: 'select', select: 'select',
multi_select: 'multi_select', multi_select: 'multi_select',
status: 'status',
date: 'date', date: 'date',
people: 'people', people: 'people',
files: 'files', files: 'files',
@ -660,6 +669,7 @@ export function getConditions() {
checkbox: ['equals', 'does_not_equal'], checkbox: ['equals', 'does_not_equal'],
select: ['equals', 'does_not_equal', 'is_empty', 'is_not_empty'], select: ['equals', 'does_not_equal', 'is_empty', 'is_not_empty'],
multi_select: ['contains', 'does_not_equal', 'is_empty', 'is_not_empty'], multi_select: ['contains', 'does_not_equal', 'is_empty', 'is_not_empty'],
status: ['equals', 'does_not_equal'],
date: [ date: [
'equals', 'equals',
'before', 'before',
@ -934,3 +944,28 @@ export function validateJSON(json: string | undefined): any {
} }
return result; return result;
} }
/**
* Manually extract a richtext's database mention RLC parameter.
* @param blockValues the blockUi.blockValues node parameter.
*/
export function extractDatabaseMentionRLC(blockValues: IDataObject[]) {
blockValues.forEach(bv => {
if (bv.richText && bv.text) {
const texts = (bv.text as { text: [{ textType: string, mentionType: string, database: string | { value: string, mode: string, __rl: boolean, __regex: string } }] }).text;
texts.forEach(txt => {
if (txt.textType === 'mention' && txt.mentionType === 'database') {
if (typeof txt.database === 'object' && txt.database.__rl) {
if (txt.database.__regex) {
const regex = new RegExp(txt.database.__regex);
const extracted = regex.exec(txt.database.value);
txt.database = extracted![1];
} else {
txt.database = txt.database.value;
}
}
}
});
}
});
}

View file

@ -12,6 +12,7 @@ import {
import { notionApiRequest, simplifyObjects } from './GenericFunctions'; import { notionApiRequest, simplifyObjects } from './GenericFunctions';
import moment from 'moment'; import moment from 'moment';
import { getDatabases } from './SearchFunctions';
export class NotionTrigger implements INodeType { export class NotionTrigger implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -61,21 +62,70 @@ export class NotionTrigger implements INodeType {
default: '', default: '',
}, },
{ {
displayName: 'Database Name or ID', displayName: 'Database',
name: 'databaseId', name: 'databaseId',
type: 'options', type: 'resourceLocator',
typeOptions: { default: { mode: 'list', value: '' },
loadOptionsMethod: 'getDatabases', required: true,
}, modes: [
{
displayName: 'Database',
name: 'list',
type: 'list',
placeholder: 'Select a Database...',
typeOptions: {
searchListMethod: 'getDatabases',
searchable: true,
},
},
{
displayName: 'Link',
name: 'url',
type: 'string',
placeholder:
'https://www.notion.so/0fe2f7de558b471eab07e9d871cdf4a9?v=f2d424ba0c404733a3f500c78c881610',
validation: [
{
type: 'regex',
properties: {
regex:
'(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*',
errorMessage: 'Not a valid Notion Database URL',
},
},
],
extractValue: {
type: 'regex',
regex: '(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})',
},
},
{
displayName: 'ID',
name: 'id',
type: 'string',
placeholder: 'ab1545b247fb49fa92d6f4b49f4d8116',
validation: [
{
type: 'regex',
properties: {
regex: '^(([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})|([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}))[ \t]*',
errorMessage: 'Not a valid Notion Database ID',
},
},
],
extractValue: {
type: 'regex',
regex: '^([0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12})',
},
url: '=https://www.notion.so/{{$value.replace(/-/g, "")}}',
},
],
displayOptions: { displayOptions: {
show: { show: {
event: ['pageAddedToDatabase', 'pagedUpdatedInDatabase'], event: ['pageAddedToDatabase', 'pagedUpdatedInDatabase'],
}, },
}, },
default: '', description: "The Notion Database to operate on",
required: true,
description:
'The ID of this database. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Simplify', displayName: 'Simplify',
@ -94,36 +144,14 @@ export class NotionTrigger implements INodeType {
}; };
methods = { methods = {
loadOptions: { listSearch: {
async getDatabases(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { getDatabases,
const returnData: INodePropertyOptions[] = [];
const { results: databases } = await notionApiRequest.call(this, 'POST', `/search`, {
page_size: 100,
filter: { property: 'object', value: 'database' },
});
for (const database of databases) {
returnData.push({
name: database.title[0]?.plain_text || database.id,
value: database.id,
});
}
returnData.sort((a, b) => {
if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) {
return -1;
}
if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) {
return 1;
}
return 0;
});
return returnData;
},
}, },
}; };
async poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null> { async poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null> {
const webhookData = this.getWorkflowStaticData('node'); const webhookData = this.getWorkflowStaticData('node');
const databaseId = this.getNodeParameter('databaseId') as string; const databaseId = this.getNodeParameter('databaseId', '', { extractValue: true }) as string;
const event = this.getNodeParameter('event') as string; const event = this.getNodeParameter('event') as string;
const simple = this.getNodeParameter('simple') as boolean; const simple = this.getNodeParameter('simple') as boolean;

View file

@ -76,11 +76,54 @@ export const pageFields: INodeProperties[] = [
/* page:archive */ /* page:archive */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Page Link or ID', displayName: 'Page',
name: 'pageId', name: 'pageId',
type: 'string', type: 'resourceLocator',
default: '', default: { mode: 'url', value: '' },
required: true, required: true,
modes: [
{
displayName: 'Link',
name: 'url',
type: 'string',
placeholder:
'https://www.notion.so/My-Page-b4eeb113e118403aa450af65ac25f0b9',
validation: [
{
type: 'regex',
properties: {
regex:
'(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*',
errorMessage: 'Not a valid Notion Page URL',
},
},
],
extractValue: {
type: 'regex',
regex: '(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})',
},
},
{
displayName: 'ID',
name: 'id',
type: 'string',
placeholder: 'ab1545b247fb49fa92d6f4b49f4d8116',
validation: [
{
type: 'regex',
properties: {
regex: '^(([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})|([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}))[ \t]*',
errorMessage: 'Not a valid Notion Page ID',
},
},
],
extractValue: {
type: 'regex',
regex: '^([0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12})',
},
url: '=https://www.notion.so/{{$value.replace(/-/g, "")}}',
},
],
displayOptions: { displayOptions: {
show: { show: {
version: [2], version: [2],
@ -88,8 +131,7 @@ export const pageFields: INodeProperties[] = [
operation: ['archive'], operation: ['archive'],
}, },
}, },
description: description: "The Notion Page to archive",
"The Page URL from Notion's 'copy link' functionality (or just the ID contained within the URL)",
}, },
{ {
displayName: 'Simplify', displayName: 'Simplify',
@ -109,19 +151,61 @@ export const pageFields: INodeProperties[] = [
/* page:create */ /* page:create */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Parent Page ID or Link', displayName: 'Parent Page',
name: 'pageId', name: 'pageId',
type: 'string', type: 'resourceLocator',
default: '', default: { mode: 'url', value: '' },
required: true, required: true,
modes: [
{
displayName: 'Link',
name: 'url',
type: 'string',
placeholder:
'https://www.notion.so/My-Page-b4eeb113e118403aa450af65ac25f0b9',
validation: [
{
type: 'regex',
properties: {
regex:
'(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}).*',
errorMessage: 'Not a valid Notion Page URL',
},
},
],
extractValue: {
type: 'regex',
regex: '(?:https|http):\/\/www.notion.so\/(?:[a-z0-9\-]{2,}\/)?(?:[a-zA-Z0-9\-]{2,}-)?([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})',
},
},
{
displayName: 'ID',
name: 'id',
type: 'string',
placeholder: 'ab1545b247fb49fa92d6f4b49f4d8116',
validation: [
{
type: 'regex',
properties: {
regex: '^(([0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12})|([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}))[ \t]*',
errorMessage: 'Not a valid Notion Page ID',
},
},
],
extractValue: {
type: 'regex',
regex: '^([0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12})',
},
url: '=https://www.notion.so/{{$value.replace(/-/g, "")}}',
},
],
displayOptions: { displayOptions: {
show: { show: {
resource: ['page'], resource: ['page'],
operation: ['create'], operation: ['create'],
}, },
}, },
description: description: "The Notion Database Page to create a child page for",
"The URL from Notion's 'copy link' functionality (or just the ID contained within the URL)",
}, },
{ {
displayName: 'Title', displayName: 'Title',

View file

@ -0,0 +1,38 @@
import { IDataObject, ILoadOptionsFunctions, INodeListSearchItems, INodeListSearchResult } from "n8n-workflow";
import { notionApiRequestAllItems } from "./GenericFunctions";
export async function getDatabases(
this: ILoadOptionsFunctions,
filter?: string,
): Promise<INodeListSearchResult> {
const returnData: INodeListSearchItems[] = [];
const body: IDataObject = {
page_size: 100,
query: filter,
filter: { property: 'object', value: 'database' },
};
const databases = await notionApiRequestAllItems.call(
this,
'results',
'POST',
`/search`,
body,
);
for (const database of databases) {
returnData.push({
name: database.title[0]?.plain_text || database.id,
value: database.id,
url: database.url,
});
}
returnData.sort((a, b) => {
if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) {
return -1;
}
if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) {
return 1;
}
return 0;
});
return { results: returnData };
}

View file

@ -12,6 +12,7 @@ import {
import { import {
extractDatabaseId, extractDatabaseId,
extractDatabaseMentionRLC,
extractPageId, extractPageId,
formatBlocks, formatBlocks,
formatTitle, formatTitle,
@ -27,6 +28,7 @@ import {
import moment from 'moment-timezone'; import moment from 'moment-timezone';
import { versionDescription } from './VersionDescription'; import { versionDescription } from './VersionDescription';
import { getDatabases } from '../SearchFunctions';
export class NotionV1 implements INodeType { export class NotionV1 implements INodeType {
description: INodeTypeDescription; description: INodeTypeDescription;
@ -39,40 +41,13 @@ export class NotionV1 implements INodeType {
} }
methods = { methods = {
listSearch: {
getDatabases,
},
loadOptions: { loadOptions: {
async getDatabases(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const body: IDataObject = {
page_size: 100,
filter: { property: 'object', value: 'database' },
};
const databases = await notionApiRequestAllItems.call(
this,
'results',
'POST',
`/search`,
body,
);
for (const database of databases) {
returnData.push({
name: database.title[0]?.plain_text || database.id,
value: database.id,
});
}
returnData.sort((a, b) => {
if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) {
return -1;
}
if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) {
return 1;
}
return 0;
});
return returnData;
},
async getDatabaseProperties(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getDatabaseProperties(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const databaseId = this.getCurrentNodeParameter('databaseId') as string; const databaseId = this.getCurrentNodeParameter('databaseId', { extractValue: true }) as string;
const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`);
for (const key of Object.keys(properties)) { for (const key of Object.keys(properties)) {
//remove parameters that cannot be set from the API. //remove parameters that cannot be set from the API.
@ -106,7 +81,7 @@ export class NotionV1 implements INodeType {
}, },
async getFilterProperties(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getFilterProperties(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const databaseId = this.getCurrentNodeParameter('databaseId') as string; const databaseId = this.getCurrentNodeParameter('databaseId', { extractValue: true }) as string;
const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`);
for (const key of Object.keys(properties)) { for (const key of Object.keys(properties)) {
returnData.push({ returnData.push({
@ -130,7 +105,7 @@ export class NotionV1 implements INodeType {
}, },
async getPropertySelectValues(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getPropertySelectValues(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|'); const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|');
const databaseId = this.getCurrentNodeParameter('databaseId') as string; const databaseId = this.getCurrentNodeParameter('databaseId', { extractValue: true }) as string;
const resource = this.getCurrentNodeParameter('resource') as string; const resource = this.getCurrentNodeParameter('resource') as string;
const operation = this.getCurrentNodeParameter('operation') as string; const operation = this.getCurrentNodeParameter('operation') as string;
const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`);
@ -167,7 +142,7 @@ export class NotionV1 implements INodeType {
}, },
async getDatabaseIdFromPage(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getDatabaseIdFromPage(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const pageId = this.getCurrentNodeParameter('pageId') as string; const pageId = extractPageId(this.getCurrentNodeParameter('pageId', { extractValue: true }) as string);
const { const {
parent: { database_id: databaseId }, parent: { database_id: databaseId },
} = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`); } = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`);
@ -205,7 +180,7 @@ export class NotionV1 implements INodeType {
async getDatabaseOptionsFromPage( async getDatabaseOptionsFromPage(
this: ILoadOptionsFunctions, this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> { ): Promise<INodePropertyOptions[]> {
const pageId = this.getCurrentNodeParameter('pageId') as string; const pageId = extractPageId(this.getCurrentNodeParameter('pageId', { extractValue: true }) as string);
const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|'); const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|');
const { const {
parent: { database_id: databaseId }, parent: { database_id: databaseId },
@ -253,11 +228,11 @@ export class NotionV1 implements INodeType {
if (resource === 'block') { if (resource === 'block') {
if (operation === 'append') { if (operation === 'append') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const blockId = extractPageId(this.getNodeParameter('blockId', i) as string); const blockId = extractPageId(this.getNodeParameter('blockId', i, '', { extractValue: true }) as string);
const blockValues = this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[];
extractDatabaseMentionRLC(blockValues);
const body: IDataObject = { const body: IDataObject = {
children: formatBlocks( children: formatBlocks(blockValues),
this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[],
),
}; };
const block = await notionApiRequest.call( const block = await notionApiRequest.call(
this, this,
@ -276,7 +251,7 @@ export class NotionV1 implements INodeType {
if (operation === 'getAll') { if (operation === 'getAll') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const blockId = extractPageId(this.getNodeParameter('blockId', i) as string); const blockId = extractPageId(this.getNodeParameter('blockId', i, '', { extractValue: true }) as string);
const returnAll = this.getNodeParameter('returnAll', i) as boolean; const returnAll = this.getNodeParameter('returnAll', i) as boolean;
if (returnAll) { if (returnAll) {
responseData = await notionApiRequestAllItems.call( responseData = await notionApiRequestAllItems.call(
@ -310,7 +285,7 @@ export class NotionV1 implements INodeType {
if (resource === 'database') { if (resource === 'database') {
if (operation === 'get') { if (operation === 'get') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const databaseId = extractDatabaseId(this.getNodeParameter('databaseId', i) as string); const databaseId = extractDatabaseId(this.getNodeParameter('databaseId', i, '', { extractValue: true }) as string);
responseData = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); responseData = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`);
const executionData = this.helpers.constructExecutionMetaData( const executionData = this.helpers.constructExecutionMetaData(
@ -359,7 +334,7 @@ export class NotionV1 implements INodeType {
parent: {}, parent: {},
properties: {}, properties: {},
}; };
body.parent['database_id'] = this.getNodeParameter('databaseId', i) as string; body.parent['database_id'] = this.getNodeParameter('databaseId', i, '', { extractValue: true }) as string;
const properties = this.getNodeParameter( const properties = this.getNodeParameter(
'propertiesUi.propertyValues', 'propertiesUi.propertyValues',
i, i,
@ -368,9 +343,9 @@ export class NotionV1 implements INodeType {
if (properties.length !== 0) { if (properties.length !== 0) {
body.properties = mapProperties(properties, timezone) as IDataObject; body.properties = mapProperties(properties, timezone) as IDataObject;
} }
body.children = formatBlocks( const blockValues = this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[];
this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[], extractDatabaseMentionRLC(blockValues);
); body.children = formatBlocks(blockValues);
responseData = await notionApiRequest.call(this, 'POST', '/pages', body); responseData = await notionApiRequest.call(this, 'POST', '/pages', body);
if (simple === true) { if (simple === true) {
responseData = simplifyObjects(responseData, false, 1); responseData = simplifyObjects(responseData, false, 1);
@ -387,7 +362,7 @@ export class NotionV1 implements INodeType {
if (operation === 'getAll') { if (operation === 'getAll') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const simple = this.getNodeParameter('simple', 0) as boolean; const simple = this.getNodeParameter('simple', 0) as boolean;
const databaseId = this.getNodeParameter('databaseId', i) as string; const databaseId = this.getNodeParameter('databaseId', i, '', { extractValue: true }) as string;
const returnAll = this.getNodeParameter('returnAll', i) as boolean; const returnAll = this.getNodeParameter('returnAll', i) as boolean;
const filters = this.getNodeParameter('options.filter', i, {}) as IDataObject; const filters = this.getNodeParameter('options.filter', i, {}) as IDataObject;
const sort = this.getNodeParameter('options.sort.sortValue', i, []) as IDataObject[]; const sort = this.getNodeParameter('options.sort.sortValue', i, []) as IDataObject[];
@ -451,7 +426,7 @@ export class NotionV1 implements INodeType {
if (operation === 'update') { if (operation === 'update') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const pageId = extractPageId(this.getNodeParameter('pageId', i) as string); const pageId = extractPageId(this.getNodeParameter('pageId', i, '', { extractValue: true }) as string);
const simple = this.getNodeParameter('simple', i) as boolean; const simple = this.getNodeParameter('simple', i) as boolean;
const properties = this.getNodeParameter( const properties = this.getNodeParameter(
'propertiesUi.propertyValues', 'propertiesUi.propertyValues',
@ -521,11 +496,11 @@ export class NotionV1 implements INodeType {
parent: {}, parent: {},
properties: {}, properties: {},
}; };
body.parent['page_id'] = extractPageId(this.getNodeParameter('pageId', i) as string); body.parent['page_id'] = extractPageId(this.getNodeParameter('pageId', i, '', { extractValue: true }) as string);
body.properties = formatTitle(this.getNodeParameter('title', i) as string); body.properties = formatTitle(this.getNodeParameter('title', i) as string);
body.children = formatBlocks( const blockValues = this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[];
this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[], extractDatabaseMentionRLC(blockValues);
); body.children = formatBlocks(blockValues);
responseData = await notionApiRequest.call(this, 'POST', '/pages', body); responseData = await notionApiRequest.call(this, 'POST', '/pages', body);
if (simple === true) { if (simple === true) {
responseData = simplifyObjects(responseData, false, 1); responseData = simplifyObjects(responseData, false, 1);

View file

@ -15,6 +15,7 @@ import {
import { import {
downloadFiles, downloadFiles,
extractDatabaseId, extractDatabaseId,
extractDatabaseMentionRLC,
extractPageId, extractPageId,
formatBlocks, formatBlocks,
formatTitle, formatTitle,
@ -31,6 +32,7 @@ import {
import moment from 'moment-timezone'; import moment from 'moment-timezone';
import { versionDescription } from './VersionDescription'; import { versionDescription } from './VersionDescription';
import { getDatabases } from '../SearchFunctions';
export class NotionV2 implements INodeType { export class NotionV2 implements INodeType {
description: INodeTypeDescription; description: INodeTypeDescription;
@ -43,40 +45,13 @@ export class NotionV2 implements INodeType {
} }
methods = { methods = {
listSearch: {
getDatabases,
},
loadOptions: { loadOptions: {
async getDatabases(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const body: IDataObject = {
page_size: 100,
filter: { property: 'object', value: 'database' },
};
const databases = await notionApiRequestAllItems.call(
this,
'results',
'POST',
`/search`,
body,
);
for (const database of databases) {
returnData.push({
name: database.title[0]?.plain_text || database.id,
value: database.id,
});
}
returnData.sort((a, b) => {
if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) {
return -1;
}
if (a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase()) {
return 1;
}
return 0;
});
return returnData;
},
async getDatabaseProperties(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getDatabaseProperties(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const databaseId = this.getCurrentNodeParameter('databaseId') as string; const databaseId = this.getCurrentNodeParameter('databaseId', { extractValue: true }) as string;
const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`);
for (const key of Object.keys(properties)) { for (const key of Object.keys(properties)) {
//remove parameters that cannot be set from the API. //remove parameters that cannot be set from the API.
@ -109,7 +84,7 @@ export class NotionV2 implements INodeType {
}, },
async getFilterProperties(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getFilterProperties(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const databaseId = this.getCurrentNodeParameter('databaseId') as string; const databaseId = this.getCurrentNodeParameter('databaseId', { extractValue: true }) as string;
const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`);
for (const key of Object.keys(properties)) { for (const key of Object.keys(properties)) {
returnData.push({ returnData.push({
@ -133,18 +108,18 @@ export class NotionV2 implements INodeType {
}, },
async getPropertySelectValues(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getPropertySelectValues(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|'); const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|');
const databaseId = this.getCurrentNodeParameter('databaseId') as string; const databaseId = this.getCurrentNodeParameter('databaseId', { extractValue: true }) as string;
const resource = this.getCurrentNodeParameter('resource') as string; const resource = this.getCurrentNodeParameter('resource') as string;
const operation = this.getCurrentNodeParameter('operation') as string; const operation = this.getCurrentNodeParameter('operation') as string;
const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`);
if (resource === 'databasePage') { if (resource === 'databasePage') {
if (['multi_select', 'select'].includes(type) && operation === 'getAll') { if (['multi_select', 'select', 'status'].includes(type) && operation === 'getAll') {
return properties[name][type].options.map((option: IDataObject) => ({ return properties[name][type].options.map((option: IDataObject) => ({
name: option.name, name: option.name,
value: option.name, value: option.name,
})); }));
} else if ( } else if (
['multi_select', 'select'].includes(type) && ['multi_select', 'select', 'status'].includes(type) &&
['create', 'update'].includes(operation) ['create', 'update'].includes(operation)
) { ) {
return properties[name][type].options.map((option: IDataObject) => ({ return properties[name][type].options.map((option: IDataObject) => ({
@ -173,7 +148,7 @@ export class NotionV2 implements INodeType {
}, },
async getDatabaseIdFromPage(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getDatabaseIdFromPage(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const pageId = extractPageId(this.getCurrentNodeParameter('pageId') as string); const pageId = extractPageId(this.getCurrentNodeParameter('pageId', { extractValue: true }) as string);
const { const {
parent: { database_id: databaseId }, parent: { database_id: databaseId },
} = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`); } = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`);
@ -211,7 +186,7 @@ export class NotionV2 implements INodeType {
async getDatabaseOptionsFromPage( async getDatabaseOptionsFromPage(
this: ILoadOptionsFunctions, this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> { ): Promise<INodePropertyOptions[]> {
const pageId = extractPageId(this.getCurrentNodeParameter('pageId') as string); const pageId = extractPageId(this.getCurrentNodeParameter('pageId', { extractValue: true }) as string);
const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|'); const [name, type] = (this.getCurrentNodeParameter('&key') as string).split('|');
const { const {
parent: { database_id: databaseId }, parent: { database_id: databaseId },
@ -260,11 +235,11 @@ export class NotionV2 implements INodeType {
if (resource === 'block') { if (resource === 'block') {
if (operation === 'append') { if (operation === 'append') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const blockId = extractPageId(this.getNodeParameter('blockId', i) as string); const blockId = extractPageId(this.getNodeParameter('blockId', i, '', { extractValue: true }) as string);
const blockValues = this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[];
extractDatabaseMentionRLC(blockValues);
const body: IDataObject = { const body: IDataObject = {
children: formatBlocks( children: formatBlocks(blockValues),
this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[],
),
}; };
const block = await notionApiRequest.call( const block = await notionApiRequest.call(
this, this,
@ -283,7 +258,7 @@ export class NotionV2 implements INodeType {
if (operation === 'getAll') { if (operation === 'getAll') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const blockId = extractPageId(this.getNodeParameter('blockId', i) as string); const blockId = extractPageId(this.getNodeParameter('blockId', i, '', { extractValue: true }) as string);
const returnAll = this.getNodeParameter('returnAll', i) as boolean; const returnAll = this.getNodeParameter('returnAll', i) as boolean;
if (returnAll) { if (returnAll) {
@ -325,7 +300,7 @@ export class NotionV2 implements INodeType {
if (operation === 'get') { if (operation === 'get') {
const simple = this.getNodeParameter('simple', 0) as boolean; const simple = this.getNodeParameter('simple', 0) as boolean;
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const databaseId = extractDatabaseId(this.getNodeParameter('databaseId', i) as string); const databaseId = extractDatabaseId(this.getNodeParameter('databaseId', i, '', { extractValue: true }) as string);
responseData = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); responseData = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`);
if (simple === true) { if (simple === true) {
responseData = simplifyObjects(responseData, download)[0]; responseData = simplifyObjects(responseData, download)[0];
@ -426,7 +401,7 @@ export class NotionV2 implements INodeType {
if (resource === 'databasePage') { if (resource === 'databasePage') {
if (operation === 'create') { if (operation === 'create') {
const databaseId = this.getNodeParameter('databaseId', 0) as string; const databaseId = this.getNodeParameter('databaseId', 0, '', { extractValue: true }) as string;
const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`); const { properties } = await notionApiRequest.call(this, 'GET', `/databases/${databaseId}`);
let titleKey = ''; let titleKey = '';
for (const key of Object.keys(properties)) { for (const key of Object.keys(properties)) {
@ -453,7 +428,7 @@ export class NotionV2 implements INodeType {
], ],
}; };
} }
body.parent['database_id'] = this.getNodeParameter('databaseId', i) as string; body.parent['database_id'] = this.getNodeParameter('databaseId', i, '', { extractValue: true }) as string;
const properties = this.getNodeParameter( const properties = this.getNodeParameter(
'propertiesUi.propertyValues', 'propertiesUi.propertyValues',
i, i,
@ -465,9 +440,9 @@ export class NotionV2 implements INodeType {
mapProperties(properties, timezone, 2) as IDataObject, mapProperties(properties, timezone, 2) as IDataObject,
); );
} }
body.children = formatBlocks( const blockValues = this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[];
this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[], extractDatabaseMentionRLC(blockValues);
); body.children = formatBlocks(blockValues);
responseData = await notionApiRequest.call(this, 'POST', '/pages', body); responseData = await notionApiRequest.call(this, 'POST', '/pages', body);
if (simple === true) { if (simple === true) {
responseData = simplifyObjects(responseData); responseData = simplifyObjects(responseData);
@ -483,7 +458,7 @@ export class NotionV2 implements INodeType {
if (operation === 'get') { if (operation === 'get') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const pageId = extractPageId(this.getNodeParameter('pageId', i) as string); const pageId = extractPageId(this.getNodeParameter('pageId', i, '', { extractValue: true }) as string);
const simple = this.getNodeParameter('simple', i) as boolean; const simple = this.getNodeParameter('simple', i) as boolean;
responseData = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`); responseData = await notionApiRequest.call(this, 'GET', `/pages/${pageId}`);
if (simple === true) { if (simple === true) {
@ -502,7 +477,7 @@ export class NotionV2 implements INodeType {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
download = this.getNodeParameter('options.downloadFiles', 0, false) as boolean; download = this.getNodeParameter('options.downloadFiles', 0, false) as boolean;
const simple = this.getNodeParameter('simple', 0) as boolean; const simple = this.getNodeParameter('simple', 0) as boolean;
const databaseId = this.getNodeParameter('databaseId', i) as string; const databaseId = this.getNodeParameter('databaseId', i, '', { extractValue: true }) as string;
const returnAll = this.getNodeParameter('returnAll', i) as boolean; const returnAll = this.getNodeParameter('returnAll', i) as boolean;
const filterType = this.getNodeParameter('filterType', 0) as string; const filterType = this.getNodeParameter('filterType', 0) as string;
const conditions = this.getNodeParameter('filters.conditions', i, []) as IDataObject[]; const conditions = this.getNodeParameter('filters.conditions', i, []) as IDataObject[];
@ -577,7 +552,7 @@ export class NotionV2 implements INodeType {
if (operation === 'update') { if (operation === 'update') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const pageId = extractPageId(this.getNodeParameter('pageId', i) as string); const pageId = extractPageId(this.getNodeParameter('pageId', i, '', { extractValue: true }) as string);
const simple = this.getNodeParameter('simple', i) as boolean; const simple = this.getNodeParameter('simple', i) as boolean;
const properties = this.getNodeParameter( const properties = this.getNodeParameter(
'propertiesUi.propertyValues', 'propertiesUi.propertyValues',
@ -641,7 +616,7 @@ export class NotionV2 implements INodeType {
if (resource === 'page') { if (resource === 'page') {
if (operation === 'archive') { if (operation === 'archive') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const pageId = extractPageId(this.getNodeParameter('pageId', i) as string); const pageId = extractPageId(this.getNodeParameter('pageId', i, '', { extractValue: true }) as string);
const simple = this.getNodeParameter('simple', i) as boolean; const simple = this.getNodeParameter('simple', i) as boolean;
responseData = await notionApiRequest.call(this, 'PATCH', `/pages/${pageId}`, { responseData = await notionApiRequest.call(this, 'PATCH', `/pages/${pageId}`, {
archived: true, archived: true,
@ -666,11 +641,11 @@ export class NotionV2 implements INodeType {
parent: {}, parent: {},
properties: {}, properties: {},
}; };
body.parent['page_id'] = extractPageId(this.getNodeParameter('pageId', i) as string); body.parent['page_id'] = extractPageId(this.getNodeParameter('pageId', i, '', { extractValue: true }) as string);
body.properties = formatTitle(this.getNodeParameter('title', i) as string); body.properties = formatTitle(this.getNodeParameter('title', i) as string);
body.children = formatBlocks( const blockValues = this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[];
this.getNodeParameter('blockUi.blockValues', i, []) as IDataObject[], extractDatabaseMentionRLC(blockValues);
); body.children = formatBlocks(blockValues);
responseData = await notionApiRequest.call(this, 'POST', '/pages', body); responseData = await notionApiRequest.call(this, 'POST', '/pages', body);
if (simple === true) { if (simple === true) {
responseData = simplifyObjects(responseData, download); responseData = simplifyObjects(responseData, download);

View file

@ -663,7 +663,10 @@ export interface ILoadOptionsFunctions {
fallbackValue?: any, fallbackValue?: any,
options?: IGetNodeParameterOptions, options?: IGetNodeParameterOptions,
): NodeParameterValueType | object; ): NodeParameterValueType | object;
getCurrentNodeParameter(parameterName: string): NodeParameterValueType | object | undefined; getCurrentNodeParameter(
parameterName: string,
options?: IGetNodeParameterOptions,
): NodeParameterValueType | object | undefined;
getCurrentNodeParameters(): INodeParameters | undefined; getCurrentNodeParameters(): INodeParameters | undefined;
getTimezone(): string; getTimezone(): string;
getRestApiUrl(): string; getRestApiUrl(): string;