{ "id": "7cd51434-9767-450f-8742-27857367f8c2", "data": { "nodes": [ { "id": "RecordsToText-Q69g5", "type": "genericNode", "position": { "x": -2671.5528488127866, "y": -963.4266471378126 }, "data": { "type": "RecordsToText", "node": { "template": { "code": { "type": "code", "required": true, "placeholder": "", "list": false, "show": true, "multiline": true, "value": "import requests\r\nfrom typing import List\r\n\r\nfrom langflow import CustomComponent\r\nfrom langflow.schema import Record\r\n\r\n\r\nclass NotionUserList(CustomComponent):\r\n display_name = \"List Users [Notion]\"\r\n description = \"Retrieve users from Notion.\"\r\n documentation: str = \"https://docs.langflow.org/integrations/notion/list-users\"\r\n icon = \"NotionDirectoryLoader\"\r\n \r\n def build_config(self):\r\n return {\r\n \"notion_secret\": {\r\n \"display_name\": \"Notion Secret\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The Notion integration token.\",\r\n \"password\": True,\r\n },\r\n }\r\n\r\n def build(\r\n self,\r\n notion_secret: str,\r\n ) -> List[Record]:\r\n url = \"https://api.notion.com/v1/users\"\r\n headers = {\r\n \"Authorization\": f\"Bearer {notion_secret}\",\r\n \"Notion-Version\": \"2022-06-28\",\r\n }\r\n\r\n response = requests.get(url, headers=headers)\r\n response.raise_for_status()\r\n\r\n data = response.json()\r\n results = data['results']\r\n\r\n records = []\r\n for user in results:\r\n id = user['id']\r\n type = user['type']\r\n name = user.get('name', '')\r\n avatar_url = user.get('avatar_url', '')\r\n\r\n record_data = {\r\n \"id\": id,\r\n \"type\": type,\r\n \"name\": name,\r\n \"avatar_url\": avatar_url,\r\n }\r\n\r\n output = \"User:\\n\"\r\n for key, value in record_data.items():\r\n output += f\"{key.replace('_', ' ').title()}: {value}\\n\"\r\n output += \"________________________\\n\"\r\n\r\n record = Record(text=output, data=record_data)\r\n records.append(record)\r\n\r\n self.status = \"\\n\".join(record.text for record in records)\r\n return records", "fileTypes": [], "file_path": "", "password": false, "name": "code", "advanced": true, "dynamic": true, "info": "", "load_from_db": false, "title_case": false }, "notion_secret": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": true, "name": "notion_secret", "display_name": "Notion Secret", "advanced": false, "dynamic": false, "info": "The Notion integration token.", "load_from_db": false, "title_case": false, "input_types": ["Text"], "value": "" }, "_type": "CustomComponent" }, "description": "Retrieve users from Notion.", "icon": "NotionDirectoryLoader", "base_classes": ["Record"], "display_name": "List Users [Notion] ", "documentation": "https://docs.langflow.org/integrations/notion/list-users", "custom_fields": { "notion_secret": null }, "output_types": ["Record"], "field_formatters": {}, "frozen": false, "field_order": [], "beta": false }, "id": "RecordsToText-Q69g5", "description": "Retrieve users from Notion.", "display_name": "List Users [Notion] " }, "selected": false, "width": 384, "height": 289, "dragging": false, "positionAbsolute": { "x": -2671.5528488127866, "y": -963.4266471378126 } }, { "id": "CustomComponent-PU0K5", "type": "genericNode", "position": { "x": -3077.2269116193215, "y": -960.9450220159636 }, "data": { "type": "CustomComponent", "node": { "template": { "code": { "type": "code", "required": true, "placeholder": "", "list": false, "show": true, "multiline": true, "value": "import json\r\nfrom typing import Optional\r\n\r\nimport requests\r\nfrom langflow.custom import CustomComponent\r\n\r\n\r\nclass NotionPageCreator(CustomComponent):\r\n display_name = \"Create Page [Notion]\"\r\n description = \"A component for creating Notion pages.\"\r\n documentation: str = \"https://docs.langflow.org/integrations/notion/page-create\"\r\n icon = \"NotionDirectoryLoader\"\r\n\r\n def build_config(self):\r\n return {\r\n \"database_id\": {\r\n \"display_name\": \"Database ID\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The ID of the Notion database.\",\r\n },\r\n \"notion_secret\": {\r\n \"display_name\": \"Notion Secret\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The Notion integration token.\",\r\n \"password\": True,\r\n },\r\n \"properties\": {\r\n \"display_name\": \"Properties\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The properties of the new page. Depending on your database setup, this can change. E.G: {'Task name': {'id': 'title', 'type': 'title', 'title': [{'type': 'text', 'text': {'content': 'Send Notion Components to LF', 'link': null}}]}}\",\r\n },\r\n }\r\n\r\n def build(\r\n self,\r\n database_id: str,\r\n notion_secret: str,\r\n properties: str = '{\"Task name\": {\"id\": \"title\", \"type\": \"title\", \"title\": [{\"type\": \"text\", \"text\": {\"content\": \"Send Notion Components to LF\", \"link\": null}}]}}',\r\n ) -> str:\r\n if not database_id or not properties:\r\n raise ValueError(\"Invalid input. Please provide 'database_id' and 'properties'.\")\r\n\r\n headers = {\r\n \"Authorization\": f\"Bearer {notion_secret}\",\r\n \"Content-Type\": \"application/json\",\r\n \"Notion-Version\": \"2022-06-28\",\r\n }\r\n\r\n data = {\r\n \"parent\": {\"database_id\": database_id},\r\n \"properties\": json.loads(properties),\r\n }\r\n\r\n response = requests.post(\"https://api.notion.com/v1/pages\", headers=headers, json=data)\r\n\r\n if response.status_code == 200:\r\n page_id = response.json()[\"id\"]\r\n self.status = f\"Successfully created Notion page with ID: {page_id}\\n {str(response.json())}\"\r\n return response.json()\r\n else:\r\n error_message = f\"Failed to create Notion page. Status code: {response.status_code}, Error: {response.text}\"\r\n self.status = error_message\r\n raise Exception(error_message)", "fileTypes": [], "file_path": "", "password": false, "name": "code", "advanced": true, "dynamic": true, "info": "", "load_from_db": false, "title_case": false }, "database_id": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": false, "name": "database_id", "display_name": "Database ID", "advanced": false, "dynamic": false, "info": "The ID of the Notion database.", "load_from_db": false, "title_case": false, "input_types": ["Text"] }, "notion_secret": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": true, "name": "notion_secret", "display_name": "Notion Secret", "advanced": false, "dynamic": false, "info": "The Notion integration token.", "load_from_db": false, "title_case": false, "input_types": ["Text"], "value": "" }, "properties": { "type": "str", "required": false, "placeholder": "", "list": false, "show": true, "multiline": false, "value": "{\"Task name\": {\"id\": \"title\", \"type\": \"title\", \"title\": [{\"type\": \"text\", \"text\": {\"content\": \"Send Notion Components to LF\", \"link\": null}}]}}", "fileTypes": [], "file_path": "", "password": false, "name": "properties", "display_name": "Properties", "advanced": false, "dynamic": false, "info": "The properties of the new page. Depending on your database setup, this can change. E.G: {'Task name': {'id': 'title', 'type': 'title', 'title': [{'type': 'text', 'text': {'content': 'Send Notion Components to LF', 'link': null}}]}}", "load_from_db": false, "title_case": false, "input_types": ["Text"] }, "_type": "CustomComponent" }, "description": "A component for creating Notion pages.", "icon": "NotionDirectoryLoader", "base_classes": ["object", "str", "Text"], "display_name": "Create Page [Notion] ", "documentation": "https://docs.langflow.org/integrations/notion/page-create", "custom_fields": { "database_id": null, "notion_secret": null, "properties": null }, "output_types": ["Text"], "field_formatters": {}, "frozen": false, "field_order": [], "beta": false }, "id": "CustomComponent-PU0K5", "description": "A component for creating Notion pages.", "display_name": "Create Page [Notion] " }, "selected": false, "width": 384, "height": 477, "positionAbsolute": { "x": -3077.2269116193215, "y": -960.9450220159636 }, "dragging": false }, { "id": "CustomComponent-YODla", "type": "genericNode", "position": { "x": -3485.297183150799, "y": -362.8525892356713 }, "data": { "type": "CustomComponent", "node": { "template": { "code": { "type": "code", "required": true, "placeholder": "", "list": false, "show": true, "multiline": true, "value": "import requests\r\nfrom typing import Dict\r\n\r\nfrom langflow import CustomComponent\r\nfrom langflow.schema import Record\r\n\r\n\r\nclass NotionDatabaseProperties(CustomComponent):\r\n display_name = \"List Database Properties [Notion]\"\r\n description = \"Retrieve properties of a Notion database.\"\r\n documentation: str = \"https://docs.langflow.org/integrations/notion/list-database-properties\"\r\n icon = \"NotionDirectoryLoader\"\r\n \r\n def build_config(self):\r\n return {\r\n \"database_id\": {\r\n \"display_name\": \"Database ID\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The ID of the Notion database.\",\r\n },\r\n \"notion_secret\": {\r\n \"display_name\": \"Notion Secret\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The Notion integration token.\",\r\n \"password\": True,\r\n },\r\n }\r\n\r\n def build(\r\n self,\r\n database_id: str,\r\n notion_secret: str,\r\n ) -> Record:\r\n url = f\"https://api.notion.com/v1/databases/{database_id}\"\r\n headers = {\r\n \"Authorization\": f\"Bearer {notion_secret}\",\r\n \"Notion-Version\": \"2022-06-28\", # Use the latest supported version\r\n }\r\n\r\n response = requests.get(url, headers=headers)\r\n response.raise_for_status()\r\n\r\n data = response.json()\r\n properties = data.get(\"properties\", {})\r\n\r\n record = Record(text=str(response.json()), data=properties)\r\n self.status = f\"Retrieved {len(properties)} properties from the Notion database.\\n {record.text}\"\r\n return record", "fileTypes": [], "file_path": "", "password": false, "name": "code", "advanced": true, "dynamic": true, "info": "", "load_from_db": false, "title_case": false }, "database_id": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": false, "name": "database_id", "display_name": "Database ID", "advanced": false, "dynamic": false, "info": "The ID of the Notion database.", "load_from_db": true, "title_case": false, "input_types": ["Text"], "value": "NOTION_NMSTX_DB_ID" }, "notion_secret": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": true, "name": "notion_secret", "display_name": "Notion Secret", "advanced": false, "dynamic": false, "info": "The Notion integration token.", "load_from_db": true, "title_case": false, "input_types": ["Text"], "value": "" }, "_type": "CustomComponent" }, "description": "Retrieve properties of a Notion database.", "icon": "NotionDirectoryLoader", "base_classes": ["Record"], "display_name": "List Database Properties [Notion] ", "documentation": "https://docs.langflow.org/integrations/notion/list-database-properties", "custom_fields": { "database_id": null, "notion_secret": null }, "output_types": ["Record"], "field_formatters": {}, "frozen": false, "field_order": [], "beta": false }, "id": "CustomComponent-YODla", "description": "Retrieve properties of a Notion database.", "display_name": "List Database Properties [Notion] " }, "selected": true, "width": 384, "height": 383, "dragging": false, "positionAbsolute": { "x": -3485.297183150799, "y": -362.8525892356713 } }, { "id": "CustomComponent-wHlSz", "type": "genericNode", "position": { "x": -2668.7714642455403, "y": -657.2376228212606 }, "data": { "type": "CustomComponent", "node": { "template": { "code": { "type": "code", "required": true, "placeholder": "", "list": false, "show": true, "multiline": true, "value": "import json\r\nimport requests\r\nfrom typing import Dict, Any\r\n\r\nfrom langflow import CustomComponent\r\nfrom langflow.schema import Record\r\n\r\n\r\nclass NotionPageUpdate(CustomComponent):\r\n display_name = \"Update Page Property [Notion]\"\r\n description = \"Update the properties of a Notion page.\"\r\n documentation: str = \"https://docs.langflow.org/integrations/notion/page-update\"\r\n icon = \"NotionDirectoryLoader\"\r\n\r\n def build_config(self):\r\n return {\r\n \"page_id\": {\r\n \"display_name\": \"Page ID\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The ID of the Notion page to update.\",\r\n },\r\n \"properties\": {\r\n \"display_name\": \"Properties\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The properties to update on the page (as a JSON string).\",\r\n \"multiline\": True,\r\n },\r\n \"notion_secret\": {\r\n \"display_name\": \"Notion Secret\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The Notion integration token.\",\r\n \"password\": True,\r\n },\r\n }\r\n\r\n def build(\r\n self,\r\n page_id: str,\r\n properties: str,\r\n notion_secret: str,\r\n ) -> Record:\r\n url = f\"https://api.notion.com/v1/pages/{page_id}\"\r\n headers = {\r\n \"Authorization\": f\"Bearer {notion_secret}\",\r\n \"Content-Type\": \"application/json\",\r\n \"Notion-Version\": \"2022-06-28\", # Use the latest supported version\r\n }\r\n\r\n try:\r\n parsed_properties = json.loads(properties)\r\n except json.JSONDecodeError as e:\r\n raise ValueError(\"Invalid JSON format for properties\") from e\r\n\r\n data = {\r\n \"properties\": parsed_properties\r\n }\r\n\r\n response = requests.patch(url, headers=headers, json=data)\r\n response.raise_for_status()\r\n\r\n updated_page = response.json()\r\n\r\n output = \"Updated page properties:\\n\"\r\n for prop_name, prop_value in updated_page[\"properties\"].items():\r\n output += f\"{prop_name}: {prop_value}\\n\"\r\n\r\n self.status = output\r\n return Record(data=updated_page)", "fileTypes": [], "file_path": "", "password": false, "name": "code", "advanced": true, "dynamic": true, "info": "", "load_from_db": false, "title_case": false }, "notion_secret": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": true, "name": "notion_secret", "display_name": "Notion Secret", "advanced": false, "dynamic": false, "info": "The Notion integration token.", "load_from_db": true, "title_case": false, "input_types": ["Text"], "value": "" }, "page_id": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": false, "name": "page_id", "display_name": "Page ID", "advanced": false, "dynamic": false, "info": "The ID of the Notion page to update.", "load_from_db": false, "title_case": false, "input_types": ["Text"] }, "properties": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": true, "fileTypes": [], "file_path": "", "password": false, "name": "properties", "display_name": "Properties", "advanced": false, "dynamic": false, "info": "The properties to update on the page (as a JSON string).", "load_from_db": false, "title_case": false, "input_types": ["Text"], "value": "{ \"title\": [ { \"text\": { \"content\": \"Test Page\" } } ] }" }, "_type": "CustomComponent" }, "description": "Update the properties of a Notion page.", "icon": "NotionDirectoryLoader", "base_classes": ["Record"], "display_name": "Update Page Property [Notion]", "documentation": "https://docs.langflow.org/integrations/notion/page-update", "custom_fields": { "page_id": null, "properties": null, "notion_secret": null }, "output_types": ["Record"], "field_formatters": {}, "frozen": false, "field_order": [], "beta": false }, "id": "CustomComponent-wHlSz", "description": "Update the properties of a Notion page.", "display_name": "Update Page Property [Notion]" }, "selected": false, "width": 384, "height": 477, "dragging": false, "positionAbsolute": { "x": -2668.7714642455403, "y": -657.2376228212606 } }, { "id": "CustomComponent-oelYw", "type": "genericNode", "position": { "x": -2253.1007124701327, "y": -448.47240118604134 }, "data": { "type": "CustomComponent", "node": { "template": { "code": { "type": "code", "required": true, "placeholder": "", "list": false, "show": true, "multiline": true, "value": "import requests\r\nfrom typing import Dict, Any\r\n\r\nfrom langflow import CustomComponent\r\nfrom langflow.schema import Record\r\n\r\n\r\nclass NotionPageContent(CustomComponent):\r\n display_name = \"Page Content Viewer [Notion]\"\r\n description = \"Retrieve the content of a Notion page as plain text.\"\r\n documentation: str = \"https://docs.langflow.org/integrations/notion/page-content-viewer\"\r\n icon = \"NotionDirectoryLoader\"\r\n\r\n def build_config(self):\r\n return {\r\n \"page_id\": {\r\n \"display_name\": \"Page ID\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The ID of the Notion page to retrieve.\",\r\n },\r\n \"notion_secret\": {\r\n \"display_name\": \"Notion Secret\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The Notion integration token.\",\r\n \"password\": True,\r\n },\r\n }\r\n\r\n def build(\r\n self,\r\n page_id: str,\r\n notion_secret: str,\r\n ) -> Record:\r\n blocks_url = f\"https://api.notion.com/v1/blocks/{page_id}/children?page_size=100\"\r\n headers = {\r\n \"Authorization\": f\"Bearer {notion_secret}\",\r\n \"Notion-Version\": \"2022-06-28\", # Use the latest supported version\r\n }\r\n\r\n # Retrieve the child blocks\r\n blocks_response = requests.get(blocks_url, headers=headers)\r\n blocks_response.raise_for_status()\r\n blocks_data = blocks_response.json()\r\n\r\n # Parse the blocks and extract the content as plain text\r\n content = self.parse_blocks(blocks_data[\"results\"])\r\n\r\n self.status = content\r\n return Record(data={\"content\": content}, text=content)\r\n\r\n def parse_blocks(self, blocks: list) -> str:\r\n content = \"\"\r\n for block in blocks:\r\n block_type = block[\"type\"]\r\n if block_type in [\"paragraph\", \"heading_1\", \"heading_2\", \"heading_3\", \"quote\"]:\r\n content += self.parse_rich_text(block[block_type][\"rich_text\"]) + \"\\n\\n\"\r\n elif block_type in [\"bulleted_list_item\", \"numbered_list_item\"]:\r\n content += self.parse_rich_text(block[block_type][\"rich_text\"]) + \"\\n\"\r\n elif block_type == \"to_do\":\r\n content += self.parse_rich_text(block[\"to_do\"][\"rich_text\"]) + \"\\n\"\r\n elif block_type == \"code\":\r\n content += self.parse_rich_text(block[\"code\"][\"rich_text\"]) + \"\\n\\n\"\r\n elif block_type == \"image\":\r\n content += f\"[Image: {block['image']['external']['url']}]\\n\\n\"\r\n elif block_type == \"divider\":\r\n content += \"---\\n\\n\"\r\n return content.strip()\r\n\r\n def parse_rich_text(self, rich_text: list) -> str:\r\n text = \"\"\r\n for segment in rich_text:\r\n text += segment[\"plain_text\"]\r\n return text", "fileTypes": [], "file_path": "", "password": false, "name": "code", "advanced": true, "dynamic": true, "info": "", "load_from_db": false, "title_case": false }, "notion_secret": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": true, "name": "notion_secret", "display_name": "Notion Secret", "advanced": false, "dynamic": false, "info": "The Notion integration token.", "load_from_db": true, "title_case": false, "input_types": ["Text"], "value": "" }, "page_id": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": false, "name": "page_id", "display_name": "Page ID", "advanced": false, "dynamic": false, "info": "The ID of the Notion page to retrieve.", "load_from_db": false, "title_case": false, "input_types": ["Text"] }, "_type": "CustomComponent" }, "description": "Retrieve the content of a Notion page as plain text.", "icon": "NotionDirectoryLoader", "base_classes": ["Record"], "display_name": "Page Content Viewer [Notion] ", "documentation": "https://docs.langflow.org/integrations/notion/page-content-viewer", "custom_fields": { "page_id": null, "notion_secret": null }, "output_types": ["Record"], "field_formatters": {}, "frozen": false, "field_order": [], "beta": false }, "id": "CustomComponent-oelYw", "description": "Retrieve the content of a Notion page as plain text.", "display_name": "Page Content Viewer [Notion] " }, "selected": false, "width": 384, "height": 383, "positionAbsolute": { "x": -2253.1007124701327, "y": -448.47240118604134 }, "dragging": false }, { "id": "CustomComponent-Pn52w", "type": "genericNode", "position": { "x": -3070.9222948695096, "y": -472.4537855763852 }, "data": { "type": "CustomComponent", "node": { "template": { "code": { "type": "code", "required": true, "placeholder": "", "list": false, "show": true, "multiline": true, "value": "import requests\r\nimport json\r\nfrom typing import Dict, Any, List\r\nfrom langflow.custom import CustomComponent\r\nfrom langflow.schema import Record\r\n\r\nclass NotionListPages(CustomComponent):\r\n display_name = \"List Pages [Notion]\"\r\n description = (\r\n \"Query a Notion database with filtering and sorting. \"\r\n \"The input should be a JSON string containing the 'filter' and 'sorts' objects. \"\r\n \"Example input:\\n\"\r\n '{\"filter\": {\"property\": \"Status\", \"select\": {\"equals\": \"Done\"}}, \"sorts\": [{\"timestamp\": \"created_time\", \"direction\": \"descending\"}]}'\r\n )\r\n documentation: str = \"https://docs.langflow.org/integrations/notion/list-pages\"\r\n icon = \"NotionDirectoryLoader\"\r\n\r\n field_order = [\r\n \"notion_secret\",\r\n \"database_id\",\r\n \"query_payload\",\r\n ]\r\n\r\n def build_config(self):\r\n return {\r\n \"notion_secret\": {\r\n \"display_name\": \"Notion Secret\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The Notion integration token.\",\r\n \"password\": True,\r\n },\r\n \"database_id\": {\r\n \"display_name\": \"Database ID\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The ID of the Notion database to query.\",\r\n },\r\n \"query_payload\": {\r\n \"display_name\": \"Database query\",\r\n \"field_type\": \"str\",\r\n \"info\": \"A JSON string containing the filters that will be used for querying the database. EG: {'filter': {'property': 'Status', 'status': {'equals': 'In progress'}}}\",\r\n },\r\n }\r\n\r\n def build(\r\n self,\r\n notion_secret: str,\r\n database_id: str,\r\n query_payload: str = \"{}\",\r\n ) -> List[Record]:\r\n try:\r\n query_data = json.loads(query_payload)\r\n filter_obj = query_data.get(\"filter\")\r\n sorts = query_data.get(\"sorts\", [])\r\n\r\n url = f\"https://api.notion.com/v1/databases/{database_id}/query\"\r\n headers = {\r\n \"Authorization\": f\"Bearer {notion_secret}\",\r\n \"Content-Type\": \"application/json\",\r\n \"Notion-Version\": \"2022-06-28\",\r\n }\r\n\r\n data = {\r\n \"sorts\": sorts,\r\n }\r\n\r\n if filter_obj:\r\n data[\"filter\"] = filter_obj\r\n\r\n response = requests.post(url, headers=headers, json=data)\r\n response.raise_for_status()\r\n\r\n results = response.json()\r\n records = []\r\n combined_text = f\"Pages found: {len(results['results'])}\\n\\n\"\r\n for page in results['results']:\r\n page_data = {\r\n 'id': page['id'],\r\n 'url': page['url'],\r\n 'created_time': page['created_time'],\r\n 'last_edited_time': page['last_edited_time'],\r\n 'properties': page['properties'],\r\n }\r\n\r\n text = (\r\n f\"id: {page['id']}\\n\"\r\n f\"url: {page['url']}\\n\"\r\n f\"created_time: {page['created_time']}\\n\"\r\n f\"last_edited_time: {page['last_edited_time']}\\n\"\r\n f\"properties: {json.dumps(page['properties'], indent=2)}\\n\\n\"\r\n )\r\n\r\n combined_text += text\r\n records.append(Record(text=text, data=page_data))\r\n \r\n self.status = combined_text.strip()\r\n return records\r\n\r\n except Exception as e:\r\n self.status = f\"An error occurred: {str(e)}\"\r\n return [Record(text=self.status, data=[])]", "fileTypes": [], "file_path": "", "password": false, "name": "code", "advanced": true, "dynamic": true, "info": "", "load_from_db": false, "title_case": false }, "database_id": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": false, "name": "database_id", "display_name": "Database ID", "advanced": false, "dynamic": false, "info": "The ID of the Notion database to query.", "load_from_db": true, "title_case": false, "input_types": ["Text"], "value": "NOTION_NMSTX_DB_ID" }, "notion_secret": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": true, "name": "notion_secret", "display_name": "Notion Secret", "advanced": false, "dynamic": false, "info": "The Notion integration token.", "load_from_db": true, "title_case": false, "input_types": ["Text"], "value": "" }, "query_payload": { "type": "str", "required": false, "placeholder": "", "list": false, "show": true, "multiline": false, "value": {}, "fileTypes": [], "file_path": "", "password": false, "name": "query_payload", "display_name": "Database query", "advanced": false, "dynamic": false, "info": "A JSON string containing the filters that will be used for querying the database. EG: {'filter': {'property': 'Status', 'status': {'equals': 'In progress'}}}", "load_from_db": false, "title_case": false, "input_types": ["Text"] }, "_type": "CustomComponent" }, "description": "Query a Notion database with filtering and sorting. The input should be a JSON string containing the 'filter' and 'sorts' objects. Example input:\n{\"filter\": {\"property\": \"Status\", \"select\": {\"equals\": \"Done\"}}, \"sorts\": [{\"timestamp\": \"created_time\", \"direction\": \"descending\"}]}", "icon": "NotionDirectoryLoader", "base_classes": ["Record"], "display_name": "List Pages [Notion] ", "documentation": "https://docs.langflow.org/integrations/notion/list-pages", "custom_fields": { "notion_secret": null, "database_id": null, "query_payload": null }, "output_types": ["Record"], "field_formatters": {}, "frozen": false, "field_order": ["notion_secret", "database_id", "query_payload"], "beta": false }, "id": "CustomComponent-Pn52w", "description": "Query a Notion database with filtering and sorting. The input should be a JSON string containing the 'filter' and 'sorts' objects. Example input:\n{\"filter\": {\"property\": \"Status\", \"select\": {\"equals\": \"Done\"}}, \"sorts\": [{\"timestamp\": \"created_time\", \"direction\": \"descending\"}]}", "display_name": "List Pages [Notion] " }, "selected": false, "width": 384, "height": 517, "positionAbsolute": { "x": -3070.9222948695096, "y": -472.4537855763852 }, "dragging": false }, { "id": "CustomComponent-I8Dec", "type": "genericNode", "position": { "x": -2256.686402636563, "y": -963.4541117792749 }, "data": { "type": "CustomComponent", "node": { "template": { "block_id": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": false, "name": "block_id", "display_name": "Page/Block ID", "advanced": false, "dynamic": false, "info": "The ID of the page/block to add the content.", "load_from_db": false, "title_case": false, "input_types": ["Text"] }, "code": { "type": "code", "required": true, "placeholder": "", "list": false, "show": true, "multiline": true, "value": "import json\r\nfrom typing import List, Dict, Any\r\nfrom markdown import markdown\r\nfrom bs4 import BeautifulSoup\r\nimport requests\r\n\r\nfrom langflow import CustomComponent\r\nfrom langflow.schema import Record\r\n\r\nclass AddContentToPage(CustomComponent):\r\n display_name = \"Add Content to Page [Notion]\"\r\n description = \"Convert markdown text to Notion blocks and append them to a Notion page.\"\r\n documentation: str = \"https://developers.notion.com/reference/patch-block-children\"\r\n icon = \"NotionDirectoryLoader\"\r\n\r\n def build_config(self):\r\n return {\r\n \"markdown_text\": {\r\n \"display_name\": \"Markdown Text\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The markdown text to convert to Notion blocks.\",\r\n \"multiline\": True,\r\n },\r\n \"block_id\": {\r\n \"display_name\": \"Page/Block ID\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The ID of the page/block to add the content.\",\r\n },\r\n \"notion_secret\": {\r\n \"display_name\": \"Notion Secret\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The Notion integration token.\",\r\n \"password\": True,\r\n },\r\n }\r\n\r\n def build(self, markdown_text: str, block_id: str, notion_secret: str) -> Record:\r\n html_text = markdown(markdown_text)\r\n soup = BeautifulSoup(html_text, 'html.parser')\r\n blocks = self.process_node(soup)\r\n\r\n url = f\"https://api.notion.com/v1/blocks/{block_id}/children\"\r\n headers = {\r\n \"Authorization\": f\"Bearer {notion_secret}\",\r\n \"Content-Type\": \"application/json\",\r\n \"Notion-Version\": \"2022-06-28\",\r\n }\r\n\r\n data = {\r\n \"children\": blocks,\r\n }\r\n\r\n response = requests.patch(url, headers=headers, json=data)\r\n self.status = str(response.json())\r\n response.raise_for_status()\r\n\r\n result = response.json()\r\n self.status = f\"Appended {len(blocks)} blocks to page with ID: {block_id}\"\r\n return Record(data=result, text=json.dumps(result))\r\n\r\n def process_node(self, node):\r\n blocks = []\r\n if isinstance(node, str):\r\n text = node.strip()\r\n if text:\r\n if text.startswith('#'):\r\n heading_level = text.count('#', 0, 6)\r\n heading_text = text[heading_level:].strip()\r\n if heading_level == 1:\r\n blocks.append(self.create_block('heading_1', heading_text))\r\n elif heading_level == 2:\r\n blocks.append(self.create_block('heading_2', heading_text))\r\n elif heading_level == 3:\r\n blocks.append(self.create_block('heading_3', heading_text))\r\n else:\r\n blocks.append(self.create_block('paragraph', text))\r\n elif node.name == 'h1':\r\n blocks.append(self.create_block('heading_1', node.get_text(strip=True)))\r\n elif node.name == 'h2':\r\n blocks.append(self.create_block('heading_2', node.get_text(strip=True)))\r\n elif node.name == 'h3':\r\n blocks.append(self.create_block('heading_3', node.get_text(strip=True)))\r\n elif node.name == 'p':\r\n code_node = node.find('code')\r\n if code_node:\r\n code_text = code_node.get_text()\r\n language, code = self.extract_language_and_code(code_text)\r\n blocks.append(self.create_block('code', code, language=language))\r\n elif self.is_table(str(node)):\r\n blocks.extend(self.process_table(node))\r\n else:\r\n blocks.append(self.create_block('paragraph', node.get_text(strip=True)))\r\n elif node.name == 'ul':\r\n blocks.extend(self.process_list(node, 'bulleted_list_item'))\r\n elif node.name == 'ol':\r\n blocks.extend(self.process_list(node, 'numbered_list_item'))\r\n elif node.name == 'blockquote':\r\n blocks.append(self.create_block('quote', node.get_text(strip=True)))\r\n elif node.name == 'hr':\r\n blocks.append(self.create_block('divider', ''))\r\n elif node.name == 'img':\r\n blocks.append(self.create_block('image', '', image_url=node.get('src')))\r\n elif node.name == 'a':\r\n blocks.append(self.create_block('bookmark', node.get_text(strip=True), link_url=node.get('href')))\r\n elif node.name == 'table':\r\n blocks.extend(self.process_table(node))\r\n\r\n for child in node.children:\r\n if isinstance(child, str):\r\n continue\r\n blocks.extend(self.process_node(child))\r\n\r\n return blocks\r\n\r\n def extract_language_and_code(self, code_text):\r\n lines = code_text.split('\\n')\r\n language = lines[0].strip()\r\n code = '\\n'.join(lines[1:]).strip()\r\n return language, code\r\n\r\n def is_code_block(self, text):\r\n return text.startswith('```')\r\n\r\n def extract_code_block(self, text):\r\n lines = text.split('\\n')\r\n language = lines[0].strip('`').strip()\r\n code = '\\n'.join(lines[1:]).strip('`').strip()\r\n return language, code\r\n \r\n def is_table(self, text):\r\n rows = text.split('\\n')\r\n if len(rows) < 2:\r\n return False\r\n\r\n has_separator = False\r\n for i, row in enumerate(rows):\r\n if '|' in row:\r\n cells = [cell.strip() for cell in row.split('|')]\r\n cells = [cell for cell in cells if cell] # Remove empty cells\r\n if i == 1 and all(set(cell) <= set('-|') for cell in cells):\r\n has_separator = True\r\n elif not cells:\r\n return False\r\n\r\n return has_separator and len(rows) >= 3\r\n\r\n def process_list(self, node, list_type):\r\n blocks = []\r\n for item in node.find_all('li'):\r\n item_text = item.get_text(strip=True)\r\n checked = item_text.startswith('[x]')\r\n is_checklist = item_text.startswith('[ ]') or checked\r\n\r\n if is_checklist:\r\n item_text = item_text.replace('[x]', '').replace('[ ]', '').strip()\r\n blocks.append(self.create_block('to_do', item_text, checked=checked))\r\n else:\r\n blocks.append(self.create_block(list_type, item_text))\r\n return blocks\r\n\r\n def process_table(self, node):\r\n blocks = []\r\n header_row = node.find('thead').find('tr') if node.find('thead') else None\r\n body_rows = node.find('tbody').find_all('tr') if node.find('tbody') else []\r\n\r\n if header_row or body_rows:\r\n table_width = max(len(header_row.find_all(['th', 'td'])) if header_row else 0,\r\n max(len(row.find_all(['th', 'td'])) for row in body_rows))\r\n\r\n table_block = self.create_block('table', '', table_width=table_width, has_column_header=bool(header_row))\r\n blocks.append(table_block)\r\n\r\n if header_row:\r\n header_cells = [cell.get_text(strip=True) for cell in header_row.find_all(['th', 'td'])]\r\n header_row_block = self.create_block('table_row', header_cells)\r\n blocks.append(header_row_block)\r\n\r\n for row in body_rows:\r\n cells = [cell.get_text(strip=True) for cell in row.find_all(['th', 'td'])]\r\n row_block = self.create_block('table_row', cells)\r\n blocks.append(row_block)\r\n\r\n return blocks\r\n \r\n def create_block(self, block_type: str, content: str, **kwargs) -> Dict[str, Any]:\r\n block = {\r\n \"object\": \"block\",\r\n \"type\": block_type,\r\n block_type: {},\r\n }\r\n\r\n if block_type in [\"paragraph\", \"heading_1\", \"heading_2\", \"heading_3\", \"bulleted_list_item\", \"numbered_list_item\", \"quote\"]:\r\n block[block_type][\"rich_text\"] = [\r\n {\r\n \"type\": \"text\",\r\n \"text\": {\r\n \"content\": content,\r\n },\r\n }\r\n ]\r\n elif block_type == 'to_do':\r\n block[block_type][\"rich_text\"] = [\r\n {\r\n \"type\": \"text\",\r\n \"text\": {\r\n \"content\": content,\r\n },\r\n }\r\n ]\r\n block[block_type]['checked'] = kwargs.get('checked', False)\r\n elif block_type == 'code':\r\n block[block_type]['rich_text'] = [\r\n {\r\n \"type\": \"text\",\r\n \"text\": {\r\n \"content\": content,\r\n },\r\n }\r\n ]\r\n block[block_type]['language'] = kwargs.get('language', 'plain text')\r\n elif block_type == 'image':\r\n block[block_type] = {\r\n \"type\": \"external\",\r\n \"external\": {\r\n \"url\": kwargs.get('image_url', '')\r\n }\r\n }\r\n elif block_type == 'divider':\r\n pass\r\n elif block_type == 'bookmark':\r\n block[block_type]['url'] = kwargs.get('link_url', '')\r\n elif block_type == 'table':\r\n block[block_type]['table_width'] = kwargs.get('table_width', 0)\r\n block[block_type]['has_column_header'] = kwargs.get('has_column_header', False)\r\n block[block_type]['has_row_header'] = kwargs.get('has_row_header', False)\r\n elif block_type == 'table_row':\r\n block[block_type]['cells'] = [[{'type': 'text', 'text': {'content': cell}} for cell in content]]\r\n\r\n return block", "fileTypes": [], "file_path": "", "password": false, "name": "code", "advanced": true, "dynamic": true, "info": "", "load_from_db": false, "title_case": false }, "markdown_text": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": true, "fileTypes": [], "file_path": "", "password": false, "name": "markdown_text", "display_name": "Markdown Text", "advanced": false, "dynamic": false, "info": "The markdown text to convert to Notion blocks.", "load_from_db": false, "title_case": false, "input_types": ["Text"], "value": "# Heading 1\n\n## Heading 2\n\n### Heading 3\n\nThis is a regular paragraph.\n\nHere's another paragraph with an image:\n![Image](https://example.com/image.jpg)\n\n## Checklist\n- [x] Completed task\n- [ ] Incomplete task\n- [x] Another completed task\n\n## Numbered List\n1. First item\n2. Second item\n3. Third item\n\n## Bulleted List\n- Item 1\n- Item 2\n- Item 3\n\n## Code Block\n```python\ndef hello_world():\n print(\"Hello, World!\")\n```\n\n## Quote\n> This is a blockquote.\n> It can span multiple lines.\n\n## Horizontal Rule\n---\n\n\n## Link\n[Notion API Documentation](https://developers.notion.com)\n\n" }, "notion_secret": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": true, "name": "notion_secret", "display_name": "Notion Secret", "advanced": false, "dynamic": false, "info": "The Notion integration token.", "load_from_db": true, "title_case": false, "input_types": ["Text"], "value": "" }, "_type": "CustomComponent" }, "description": "Convert markdown text to Notion blocks and append them to a Notion page.", "icon": "NotionDirectoryLoader", "base_classes": ["Record"], "display_name": "Add Content to Page [Notion] ", "documentation": "https://developers.notion.com/reference/patch-block-children", "custom_fields": { "markdown_text": null, "block_id": null, "notion_secret": null }, "output_types": ["Record"], "field_formatters": {}, "frozen": false, "field_order": [], "beta": false, "official": false }, "id": "CustomComponent-I8Dec" }, "selected": false, "width": 384, "height": 497, "positionAbsolute": { "x": -2256.686402636563, "y": -963.4541117792749 }, "dragging": false }, { "id": "CustomComponent-ZcsA9", "type": "genericNode", "position": { "x": -3488.029350341937, "y": -965.3756250644985 }, "data": { "type": "CustomComponent", "node": { "template": { "code": { "type": "code", "required": true, "placeholder": "", "list": false, "show": true, "multiline": true, "value": "import requests\r\nfrom typing import Dict, Any, List\r\nfrom langflow.custom import CustomComponent\r\nfrom langflow.schema import Record\r\n\r\nclass NotionSearch(CustomComponent):\r\n display_name = \"Search Notion\"\r\n description = (\r\n \"Searches all pages and databases that have been shared with an integration.\"\r\n )\r\n documentation: str = \"https://docs.langflow.org/integrations/notion/search\"\r\n icon = \"NotionDirectoryLoader\"\r\n\r\n field_order = [\r\n \"notion_secret\",\r\n \"query\",\r\n \"filter_value\",\r\n \"sort_direction\",\r\n ]\r\n\r\n def build_config(self):\r\n return {\r\n \"notion_secret\": {\r\n \"display_name\": \"Notion Secret\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The Notion integration token.\",\r\n \"password\": True,\r\n },\r\n \"query\": {\r\n \"display_name\": \"Search Query\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The text that the API compares page and database titles against.\",\r\n },\r\n \"filter_value\": {\r\n \"display_name\": \"Filter Type\",\r\n \"field_type\": \"str\",\r\n \"info\": \"Limits the results to either only pages or only databases.\",\r\n \"options\": [\"page\", \"database\"],\r\n \"default_value\": \"page\",\r\n },\r\n \"sort_direction\": {\r\n \"display_name\": \"Sort Direction\",\r\n \"field_type\": \"str\",\r\n \"info\": \"The direction to sort the results.\",\r\n \"options\": [\"ascending\", \"descending\"],\r\n \"default_value\": \"descending\",\r\n },\r\n }\r\n\r\n def build(\r\n self,\r\n notion_secret: str,\r\n query: str = \"\",\r\n filter_value: str = \"page\",\r\n sort_direction: str = \"descending\",\r\n ) -> List[Record]:\r\n try:\r\n url = \"https://api.notion.com/v1/search\"\r\n headers = {\r\n \"Authorization\": f\"Bearer {notion_secret}\",\r\n \"Content-Type\": \"application/json\",\r\n \"Notion-Version\": \"2022-06-28\",\r\n }\r\n\r\n data = {\r\n \"query\": query,\r\n \"filter\": {\r\n \"value\": filter_value,\r\n \"property\": \"object\"\r\n },\r\n \"sort\":{\r\n \"direction\": sort_direction,\r\n \"timestamp\": \"last_edited_time\"\r\n }\r\n }\r\n\r\n response = requests.post(url, headers=headers, json=data)\r\n response.raise_for_status()\r\n\r\n results = response.json()\r\n records = []\r\n combined_text = f\"Results found: {len(results['results'])}\\n\\n\"\r\n for result in results['results']:\r\n result_data = {\r\n 'id': result['id'],\r\n 'type': result['object'],\r\n 'last_edited_time': result['last_edited_time'],\r\n }\r\n \r\n if result['object'] == 'page':\r\n result_data['title_or_url'] = result['url']\r\n text = f\"id: {result['id']}\\ntitle_or_url: {result['url']}\\n\"\r\n elif result['object'] == 'database':\r\n if 'title' in result and isinstance(result['title'], list) and len(result['title']) > 0:\r\n result_data['title_or_url'] = result['title'][0]['plain_text']\r\n text = f\"id: {result['id']}\\ntitle_or_url: {result['title'][0]['plain_text']}\\n\"\r\n else:\r\n result_data['title_or_url'] = \"N/A\"\r\n text = f\"id: {result['id']}\\ntitle_or_url: N/A\\n\"\r\n\r\n text += f\"type: {result['object']}\\nlast_edited_time: {result['last_edited_time']}\\n\\n\"\r\n combined_text += text\r\n records.append(Record(text=text, data=result_data))\r\n \r\n self.status = combined_text\r\n return records\r\n\r\n except Exception as e:\r\n self.status = f\"An error occurred: {str(e)}\"\r\n return [Record(text=self.status, data=[])]", "fileTypes": [], "file_path": "", "password": false, "name": "code", "advanced": true, "dynamic": true, "info": "", "load_from_db": false, "title_case": false }, "filter_value": { "type": "str", "required": false, "placeholder": "", "list": true, "show": true, "multiline": false, "value": "database", "fileTypes": [], "file_path": "", "password": false, "options": ["page", "database"], "name": "filter_value", "display_name": "Filter Type", "advanced": false, "dynamic": false, "info": "Limits the results to either only pages or only databases.", "load_from_db": false, "title_case": false, "input_types": ["Text"] }, "notion_secret": { "type": "str", "required": true, "placeholder": "", "list": false, "show": true, "multiline": false, "fileTypes": [], "file_path": "", "password": true, "name": "notion_secret", "display_name": "Notion Secret", "advanced": false, "dynamic": false, "info": "The Notion integration token.", "load_from_db": true, "title_case": false, "input_types": ["Text"], "value": "" }, "query": { "type": "str", "required": false, "placeholder": "", "list": false, "show": true, "multiline": false, "value": "", "fileTypes": [], "file_path": "", "password": false, "name": "query", "display_name": "Search Query", "advanced": false, "dynamic": false, "info": "The text that the API compares page and database titles against.", "load_from_db": false, "title_case": false, "input_types": ["Text"] }, "sort_direction": { "type": "str", "required": false, "placeholder": "", "list": true, "show": true, "multiline": false, "value": "descending", "fileTypes": [], "file_path": "", "password": false, "options": ["ascending", "descending"], "name": "sort_direction", "display_name": "Sort Direction", "advanced": false, "dynamic": false, "info": "The direction to sort the results.", "load_from_db": false, "title_case": false, "input_types": ["Text"] }, "_type": "CustomComponent" }, "description": "Searches all pages and databases that have been shared with an integration.", "icon": "NotionDirectoryLoader", "base_classes": ["Record"], "display_name": "Search [Notion]", "documentation": "https://docs.langflow.org/integrations/notion/search", "custom_fields": { "notion_secret": null, "query": null, "filter_value": null, "sort_direction": null }, "output_types": ["Record"], "field_formatters": {}, "frozen": false, "field_order": [ "notion_secret", "query", "filter_value", "sort_direction" ], "beta": false }, "id": "CustomComponent-ZcsA9", "description": "Searches all pages and databases that have been shared with an integration.", "display_name": "Search [Notion]" }, "selected": false, "width": 384, "height": 591, "positionAbsolute": { "x": -3488.029350341937, "y": -965.3756250644985 }, "dragging": false } ], "edges": [], "viewport": { "x": 2623.378922967084, "y": 696.8541079344027, "zoom": 0.5981384177708997 } }, "description": "A Bundle containing Notion components for Page and Database manipulation. You can list pages, users databases, update properties, create new pages and add content to Notion Pages.", "name": "Notion - Components", "last_tested_version": "1.0.0a36", "is_component": false }