Merge pull request #61 from jxpeng98/unify-upload-functions

unify three databases with single upload file
This commit is contained in:
Jiaxin Peng
2025-10-06 23:19:55 +01:00
committed by GitHub
14 changed files with 824 additions and 1302 deletions

4
.gitignore vendored
View File

@@ -24,3 +24,7 @@ data.json
# local data
local-data
# vitepress
doc/.vitepress/dist
doc/.vitepress/cache

View File

@@ -1,7 +1,5 @@
import { App, Editor, MarkdownView, Notice, Plugin, PluginSettingTab, Setting } from "obsidian";
import { addIcons } from 'src/ui/icon';
import { Upload2NotionGeneral } from "src/upload/upload_general/Upload2NotionGeneral";
import { Upload2NotionNext } from "src/upload/upload_next/Upload2NotionNext";
import { i18nConfig } from "src/lang/I18n";
import ribbonCommands from "src/commands/NotionCommands";
import { ObsidianSettingTab, PluginSettings, DEFAULT_SETTINGS, DatabaseDetails } from "src/ui/settingTabs";
@@ -86,4 +84,3 @@ export default class ObsidianSyncNotionPlugin extends Plugin {

582
src/upload/Upload2Notion.ts Normal file
View File

@@ -0,0 +1,582 @@
import { App, TFile } from "obsidian";
import { markdownToBlocks } from "@jxpeng98/martian";
import * as yamlFrontMatter from "yaml-front-matter";
import { LIMITS, paragraph } from "@jxpeng98/martian/src/notion";
import MyPlugin from "src/main";
import { DatabaseDetails } from "../ui/settingTabs";
import { updateYamlInfo } from "./updateYaml";
import { UploadBase, NotionPageResponse } from "./common/UploadBase";
export type DatasetType = "general" | "next" | "custom";
interface BaseSyncRequest {
dataset: DatasetType;
markdown: string;
nowFile: TFile;
app: App;
}
interface GeneralSyncRequest extends BaseSyncRequest {
dataset: "general";
title: string;
cover: string;
tags: string[];
}
interface NextSyncRequest extends BaseSyncRequest {
dataset: "next";
title: string;
emoji: string;
cover: string;
tags: string[];
type: string;
slug: string;
stats: string;
category: string;
summary: string;
password: string;
favicon: string;
datetime: string;
}
interface CustomSyncRequest extends BaseSyncRequest {
dataset: "custom";
cover: string;
customValues: Record<string, string>;
}
export type SyncRequest =
| GeneralSyncRequest
| NextSyncRequest
| CustomSyncRequest;
interface GeneralParams {
title: string;
cover?: string;
tags: string[];
childArr: any[];
notionId?: string;
}
interface NextParams {
title: string;
emoji: string;
cover?: string;
tags: string[];
type: string;
slug: string;
stats: string;
category: string;
summary: string;
password: string;
favicon: string;
datetime: string;
childArr: any[];
notionId?: string;
}
interface CustomParams {
cover?: string;
customValues: Record<string, string>;
childArr: any[];
notionId?: string;
}
export class Upload2Notion extends UploadBase {
constructor(plugin: MyPlugin, dbDetails: DatabaseDetails) {
super(plugin, dbDetails);
}
async sync(request: SyncRequest): Promise<NotionPageResponse> {
console.log(`[Upload2Notion] Start sync`, {
dataset: request.dataset,
file: request.nowFile.path,
database: this.dbDetails.databaseID,
});
let response: NotionPageResponse;
switch (request.dataset) {
case "general":
response = await this.handleGeneral(request);
break;
case "next":
response = await this.handleNext(request);
break;
case "custom":
response = await this.handleCustom(request);
break;
default:
throw new Error(`Unsupported dataset type: ${(request as any).dataset}`);
}
console.log(`[Upload2Notion] Notion response status`, response.response?.status);
if (response.response && response.response.status === 200) {
console.log(`[Upload2Notion] Sync success`, {
notionPageId: response.data?.id,
notionPageUrl: response.data?.url,
});
await updateYamlInfo(
request.markdown,
request.nowFile,
response.data,
request.app,
this.plugin,
this.dbDetails,
);
} else {
console.log(`[Upload2Notion] Sync failed`, response.data);
}
return response;
}
private async handleGeneral(request: GeneralSyncRequest): Promise<NotionPageResponse> {
console.log(`[Upload2Notion] Handling general dataset`, {
cover: request.cover,
tags: request.tags,
});
const blocks = this.buildBlocks(request.markdown, {
notionLimits: {truncate: false},
});
const notionId = this.getNotionId(request.app, request.nowFile);
return this.upsertGeneral({
title: request.title,
cover: request.cover,
tags: request.tags || [],
childArr: blocks,
notionId,
});
}
private async handleNext(request: NextSyncRequest): Promise<NotionPageResponse> {
console.log(`[Upload2Notion] Handling next dataset`, {
type: request.type,
slug: request.slug,
category: request.category,
});
const blocks = this.buildBlocks(request.markdown, {
notionLimits: {truncate: false},
});
this.splitRichTextParagraphs(blocks);
const notionId = this.getNotionId(request.app, request.nowFile);
return this.upsertNext({
title: request.title,
emoji: request.emoji,
cover: request.cover,
tags: request.tags || [],
type: request.type,
slug: request.slug,
stats: request.stats,
category: request.category,
summary: request.summary,
password: request.password,
favicon: request.favicon,
datetime: request.datetime,
childArr: blocks,
notionId,
});
}
private async handleCustom(request: CustomSyncRequest): Promise<NotionPageResponse> {
console.log(`[Upload2Notion] Handling custom dataset`, {
customKeys: Object.keys(request.customValues || {}),
});
const blocks = this.buildBlocks(request.markdown, {
strictImageUrls: true,
notionLimits: {truncate: false},
});
const notionId = this.getNotionId(request.app, request.nowFile);
return this.upsertCustom({
cover: request.cover,
customValues: request.customValues,
childArr: blocks,
notionId,
});
}
private buildBlocks(markdown: string, options: Record<string, unknown>): any[] {
const yamlContent: any = yamlFrontMatter.loadFront(markdown);
const content = yamlContent.__content;
return markdownToBlocks(content, options);
}
private getNotionId(app: App, nowFile: TFile): string | undefined {
const frontMatter = app.metadataCache.getFileCache(nowFile)?.frontmatter;
if (!frontMatter) {
return undefined;
}
const {abName} = this.dbDetails;
const notionIDKey = `NotionID-${abName}`;
const notionId = frontMatter[notionIDKey];
return notionId ? String(notionId) : undefined;
}
private splitRichTextParagraphs(blocks: any[]): void {
blocks.forEach((block, index) => {
if (
block.type === "paragraph" &&
block.paragraph.rich_text.length > LIMITS.RICH_TEXT_ARRAYS
) {
console.log(`[Upload2Notion] Splitting rich text paragraph`, {
index,
length: block.paragraph.rich_text.length,
});
const paragraphChunks = this.chunkArray<any>(block.paragraph.rich_text, 100);
const newParagraphBlocks = paragraphChunks.map((chunk) => paragraph(chunk));
blocks.splice(index, 1, ...newParagraphBlocks);
}
});
}
private chunkArray<T>(items: T[], size: number): T[][] {
const result: T[][] = [];
for (let i = 0; i < items.length; i += size) {
result.push(items.slice(i, i + size));
}
return result;
}
private async upsertGeneral(params: GeneralParams): Promise<NotionPageResponse> {
const {firstChunk, extraChunks} = this.prepareBlocks(params.childArr);
const cover = params.notionId
? await this.resolveCoverForUpdate(params.cover)
: params.cover;
if (params.notionId) {
await this.deletePage(params.notionId);
}
const body = this.buildGeneralBody({
title: params.title,
tags: params.tags,
firstChunk,
});
this.applyCover(body, cover);
console.log(body);
return this.submitPage(body, extraChunks);
}
private async upsertNext(params: NextParams): Promise<NotionPageResponse> {
const {firstChunk, extraChunks} = this.prepareBlocks(params.childArr);
const cover = params.notionId
? await this.resolveCoverForUpdate(params.cover)
: params.cover;
if (params.notionId) {
await this.deletePage(params.notionId);
}
const body = this.buildNextBody({
firstChunk,
title: params.title,
emoji: params.emoji,
tags: params.tags,
type: params.type,
slug: params.slug,
stats: params.stats,
category: params.category,
summary: params.summary,
password: params.password,
favicon: params.favicon,
datetime: params.datetime,
});
this.applyCover(body, cover);
console.log(body);
return this.submitPage(body, extraChunks);
}
private async upsertCustom(params: CustomParams): Promise<NotionPageResponse> {
const {firstChunk, extraChunks} = this.prepareBlocks(params.childArr);
const cover = params.notionId
? await this.resolveCoverForUpdate(params.cover)
: params.cover;
if (params.notionId) {
await this.deletePage(params.notionId);
}
const body = this.buildCustomBody({
customValues: params.customValues,
firstChunk,
});
this.applyCover(body, cover);
console.log(body);
return this.submitPage(body, extraChunks);
}
private buildGeneralBody(params: {title: string; tags: string[]; firstChunk: any[]}): any {
const {
databaseID,
customTitleButton,
customTitleName,
tagButton,
} = this.dbDetails;
return {
parent: {
database_id: databaseID,
},
properties: {
[customTitleButton ? customTitleName : "title"]: {
title: [
{
text: {
content: params.title,
},
},
],
},
...(tagButton
? {
tags: {
multi_select:
params.tags && params.tags.length > 0
? params.tags.map((tag) => ({name: tag}))
: [],
},
}
: {}),
},
children: params.firstChunk,
};
}
private buildNextBody(params: {
firstChunk: any[];
title: string;
emoji: string;
tags: string[];
type: string;
slug: string;
stats: string;
category: string;
summary: string;
password: string;
favicon: string;
datetime: string;
}): any {
const {databaseID} = this.dbDetails;
const pageProperties: any = {
parent: {
database_id: databaseID,
},
properties: {
title: {
title: [
{
text: {
content: params.title,
},
},
],
},
type: {
select: {
name: params.type || "Post",
},
},
status: {
select: {
name: params.stats || "Draft",
},
},
category: {
select: {
name: params.category || "Obsidian",
},
},
password: {
rich_text: [
{
text: {
content: params.password || "",
},
},
],
},
icon: {
rich_text: [
{
text: {
content: params.favicon || "",
},
},
],
},
date: {
date: {
start: params.datetime || new Date().toISOString(),
},
},
},
};
if (params.tags && params.tags.length > 0) {
pageProperties.properties.tags = {
multi_select: params.tags.map((tag) => ({name: tag})),
};
}
if (params.emoji) {
pageProperties.icon = {
emoji: params.emoji,
};
}
if (params.slug) {
pageProperties.properties.slug = {
rich_text: [
{
text: {
content: params.slug,
},
},
],
};
}
if (params.summary) {
pageProperties.properties.summary = {
rich_text: [
{
text: {
content: params.summary,
},
},
],
};
}
return {
...pageProperties,
children: params.firstChunk,
};
}
private buildCustomBody(params: {
customValues: Record<string, string>;
firstChunk: any[];
}): any {
const {customProperties, databaseID} = this.dbDetails;
const properties: { [key: string]: any } = {};
if (customProperties) {
customProperties.forEach(({customName, customType}) => {
if (params.customValues[customName] !== undefined) {
const propertyValue = this.buildCustomProperty(customName, customType, params.customValues);
if (propertyValue !== undefined) {
properties[customName] = propertyValue;
}
}
});
}
return {
parent: {
database_id: databaseID,
},
properties,
children: params.firstChunk,
};
}
private buildCustomProperty(customName: string, customType: string, customValues: Record<string, any>) {
const value = customValues[customName] || "";
switch (customType) {
case "title":
return {
title: [
{
text: {
content: value,
},
},
],
};
case "rich_text":
return {
rich_text: [
{
text: {
content: value || "",
},
},
],
};
case "date":
return {
date: {
start: value || new Date().toISOString(),
},
};
case "number":
return {
number: Number(value),
};
case "phone_number":
return {
phone_number: value,
};
case "email":
return {
email: value,
};
case "url":
return {
url: value,
};
case "files":
return {
files: Array.isArray(value)
? value.map((url: string) => ({
name: url,
type: "external",
external: {
url,
},
}))
: [
{
name: value,
type: "external",
external: {
url: value,
},
},
],
};
case "checkbox":
return {
checkbox: Boolean(value) || false,
};
case "select":
return {
select: {
name: value,
},
};
case "multi_select":
return {
multi_select: Array.isArray(value)
? value.map((item: string) => ({name: item}))
: [{name: value}],
};
case "relation":
return {
relation: Array.isArray(value)
? value.map((item: string) => ({id: item}))
: [{id: value}],
};
default:
return undefined;
}
}
}

View File

@@ -0,0 +1,186 @@
import { Notice, requestUrl } from "obsidian";
import MyPlugin from "src/main";
import { DatabaseDetails } from "../../ui/settingTabs";
import { i18nConfig } from "../../lang/I18n";
export interface NotionPageResponse {
response: any;
data: any;
}
interface PreparedBlocks {
firstChunk: any[];
extraChunks: any[][];
}
export abstract class UploadBase {
protected plugin: MyPlugin;
protected dbDetails: DatabaseDetails;
protected constructor(plugin: MyPlugin, dbDetails: DatabaseDetails) {
this.plugin = plugin;
this.dbDetails = dbDetails;
}
async deletePage(notionID: string) {
const {notionAPI} = this.dbDetails;
return requestUrl({
url: `https://api.notion.com/v1/blocks/${notionID}`,
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + notionAPI,
"Notion-Version": "2022-06-28",
},
body: "",
});
}
protected prepareBlocks(childArr: any[]): PreparedBlocks {
this.stripCodeAnnotations(childArr);
const childArrLength = childArr.length;
console.log(`Page includes ${childArrLength} blocks`);
if (childArrLength <= 100) {
return {
firstChunk: childArr,
extraChunks: [],
};
}
const extraChunks: any[][] = [];
for (let i = 100; i < childArr.length; i += 100) {
extraChunks.push(childArr.slice(i, i + 100));
}
return {
firstChunk: childArr.slice(0, 100),
extraChunks,
};
}
protected applyCover(body: any, cover?: string) {
if (cover) {
body.cover = {
type: "external",
external: {
url: cover,
},
};
} else if (!body.cover && this.plugin.settings.bannerUrl) {
body.cover = {
type: "external",
external: {
url: this.plugin.settings.bannerUrl,
},
};
}
}
protected async resolveCoverForUpdate(cover?: string): Promise<string | undefined> {
if (cover) {
return cover;
}
const databaseCover = await this.fetchDatabaseCover();
return databaseCover ?? undefined;
}
protected async submitPage(body: any, extraChunks: any[][]): Promise<NotionPageResponse> {
const {notionAPI} = this.dbDetails;
const response = await requestUrl({
url: `https://api.notion.com/v1/pages`,
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + notionAPI,
"Notion-Version": "2022-06-28",
},
body: JSON.stringify(body),
throw: false,
});
const data = await response.json;
if (response.status !== 200) {
new Notice(`Error ${data.status}: ${data.code} \n ${i18nConfig["CheckConsole"]}`, 5000);
console.log(`Error message: \n ${data.message}`);
} else {
console.log(`Page created: ${data.url}`);
console.log(`Page ID: ${data.id}`);
if (extraChunks.length > 0) {
await this.appendExtraBlocks(data.id, extraChunks);
}
}
return {response, data};
}
private stripCodeAnnotations(childArr: any[]) {
childArr.forEach((block: any) => {
if (block.type === "code") {
block.code.rich_text.forEach((item: any) => {
if (item.type === "text" && item.annotations) {
delete item.annotations;
}
});
}
});
}
private async appendExtraBlocks(pageId: string, extraChunks: any[][]) {
const {notionAPI} = this.dbDetails;
for (let i = 0; i < extraChunks.length; i++) {
const chunk = extraChunks[i];
const extraBlocks = {
children: chunk,
};
console.log(extraBlocks);
const extraResponse = await requestUrl({
url: `https://api.notion.com/v1/blocks/${pageId}/children`,
method: "PATCH",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + notionAPI,
"Notion-Version": "2022-06-28",
},
body: JSON.stringify(extraBlocks),
});
const extraData: any = await extraResponse.json;
if (extraResponse.status !== 200) {
new Notice(`Error ${extraData.status}: ${extraData.code} \n ${i18nConfig["CheckConsole"]}`, 5000);
console.log(`Error message: \n ${extraData.message}`);
} else {
console.log(`${i18nConfig["ExtraBlockUploaded"]} to page: ${pageId}`);
if (i === extraChunks.length - 1) {
console.log(`${i18nConfig["BlockUploaded"]} to page: ${pageId}`);
new Notice(`${i18nConfig["BlockUploaded"]} page: ${pageId}`, 5000);
}
}
}
}
private async fetchDatabaseCover(): Promise<string | null> {
const {notionAPI, databaseID} = this.dbDetails;
const response = await requestUrl({
url: `https://api.notion.com/v1/databases/${databaseID}`,
method: "GET",
headers: {
Authorization: "Bearer " + notionAPI,
"Notion-Version": "2022-06-28",
},
});
if (response.json.cover && response.json.cover.external) {
return response.json.cover.external.url;
}
return null;
}
}

View File

@@ -24,6 +24,7 @@ export async function getNowFileMarkdownContentCustom(
.map(property => property.customName);
// Extract custom values from the front matter based on the names
// Only collect data 'Relation' should be handled separately in the function buildBodyString
customPropertyNames.forEach(propertyName => {
if (FileCache.frontmatter && FileCache.frontmatter[propertyName] !== undefined) {
customValues[propertyName] = FileCache.frontmatter[propertyName];
@@ -31,7 +32,8 @@ export async function getNowFileMarkdownContentCustom(
});
// Check if any of the customProperties has a customType of 'title'
const titleProperty = dbDetails.customProperties.find(property => property.customType === 'title');
const titleProperty = dbDetails.customProperties
.find(property => property.customType === 'title');
// If a 'title' type property exists, use the file's basename as its value
if (titleProperty) {

View File

@@ -1,13 +1,11 @@
import {i18nConfig} from "../lang/I18n";
import {App, Notice} from "obsidian";
import {Upload2NotionNext} from "./upload_next/Upload2NotionNext";
import {Upload2NotionGeneral} from "./upload_general/Upload2NotionGeneral";
import {Upload2NotionCustom} from "./upoload_custom/Upload2NotionCustom";
import {Upload2Notion} from "./Upload2Notion";
import {DatabaseDetails, PluginSettings} from "../ui/settingTabs";
import ObsidianSyncNotionPlugin from "../main";
import {getNowFileMarkdownContentNext} from "./upload_next/getMarkdownNext";
import {getNowFileMarkdownContentGeneral} from "./upload_general/getMarkdownGeneral";
import {getNowFileMarkdownContentCustom} from "./upoload_custom/getMarkdownCustom";
import {getNowFileMarkdownContentNext} from "./common/getMarkdownNext";
import {getNowFileMarkdownContentGeneral} from "./common/getMarkdownGeneral";
import {getNowFileMarkdownContentCustom} from "./common/getMarkdownCustom";
export async function uploadCommandNext(
plugin: ObsidianSyncNotionPlugin,
@@ -17,6 +15,7 @@ export async function uploadCommandNext(
) {
const {notionAPI, databaseID} = dbDetails;
console.log(`[uploadCommandNext] ${new Date().toISOString()} Triggered for file`, app.workspace.getActiveFile()?.path);
// Check if the user has set up the Notion API and database ID
if (notionAPI === "" || databaseID === "") {
@@ -44,8 +43,25 @@ export async function uploadCommandNext(
if (markDownData) {
const {basename} = nowFile;
const upload = new Upload2NotionNext(plugin, dbDetails);
const res = await upload.syncMarkdownToNotionNext(basename, emoji, cover, tags, type, slug, stats, category, summary, paword, favicon, datetime, markDownData, nowFile, this.app);
const upload = new Upload2Notion(plugin, dbDetails);
const res = await upload.sync({
dataset: "next",
title: basename,
emoji: emoji || "",
cover: cover || "",
tags: tags || [],
type: type || "",
slug: slug || "",
stats: stats || "",
category: category || "",
summary: summary || "",
password: paword || "",
favicon: favicon || "",
datetime: datetime || "",
markdown: markDownData,
nowFile,
app,
});
const {response} = res;
if (response.status === 200) {
@@ -68,6 +84,7 @@ export async function uploadCommandGeneral(
) {
const {notionAPI, databaseID} = dbDetails;
console.log(`[uploadCommandGeneral] ${new Date().toISOString()} Triggered for file`, app.workspace.getActiveFile()?.path);
// Check if the user has set up the Notion API and database ID
if (notionAPI === "" || databaseID === "") {
@@ -84,8 +101,16 @@ export async function uploadCommandGeneral(
if (markDownData) {
const {basename} = nowFile;
const upload = new Upload2NotionGeneral(plugin, dbDetails);
const res = await upload.syncMarkdownToNotionGeneral(basename, cover, tags, markDownData, nowFile, this.app);
const upload = new Upload2Notion(plugin, dbDetails);
const res = await upload.sync({
dataset: "general",
title: basename,
cover: cover || "",
tags: tags || [],
markdown: markDownData,
nowFile,
app,
});
const {response} = res;
if (response.status === 200) {
@@ -107,7 +132,8 @@ export async function uploadCommandCustom(
app: App,
) {
const {notionAPI, databaseID} = settings;
const {notionAPI, databaseID} = dbDetails;
console.log(`[uploadCommandCustom] ${new Date().toISOString()} Triggered for file`, app.workspace.getActiveFile()?.path);
// Check if the user has set up the Notion API and database ID
if (notionAPI === "" || databaseID === "") {
@@ -124,8 +150,15 @@ export async function uploadCommandCustom(
if (markDownData) {
const {basename} = nowFile;
const upload = new Upload2NotionCustom(plugin, dbDetails);
const res = await upload.syncMarkdownToNotionCustom(cover, customValues, markDownData, nowFile, this.app);
const upload = new Upload2Notion(plugin, dbDetails);
const res = await upload.sync({
dataset: "custom",
cover: cover || "",
customValues,
markdown: markDownData,
nowFile,
app,
});
const {response} = res;

View File

@@ -1,96 +0,0 @@
import { App, Notice, requestUrl, TFile } from "obsidian";
import { Client } from '@notionhq/client';
import { markdownToBlocks, } from "@jxpeng98/martian";
import * as yamlFrontMatter from "yaml-front-matter";
// import * as yaml from "yaml"
import MyPlugin from "src/main";
import { DatabaseDetails } from "../../ui/settingTabs";
export class UploadBaseGeneral {
plugin: MyPlugin;
notion: Client;
agent: any;
dbDetails: DatabaseDetails
constructor(plugin: MyPlugin, dbDetails: DatabaseDetails) {
this.plugin = plugin;
this.dbDetails = dbDetails
}
async deletePage(notionID: string) {
const { notionAPI } = this.dbDetails
return requestUrl({
url: `https://api.notion.com/v1/blocks/${notionID}`,
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + notionAPI,
'Notion-Version': '2022-06-28',
},
body: ''
});
}
async getDataBase(databaseID: string) {
const { notionAPI } = this.dbDetails
const response = await requestUrl({
url: `https://api.notion.com/v1/databases/${databaseID}`,
method: 'GET',
headers: {
'Authorization': 'Bearer ' + notionAPI,
'Notion-Version': '2022-06-28',
}
}
)
// Check if cover is present in the JSON response and then get the URL
if (response.json.cover && response.json.cover.external) {
return response.json.cover.external.url;
} else {
return null; // or some other default value, if you prefer
}
}
// async updateYamlInfo(yamlContent: string, nowFile: TFile, res: any, app: App, settings: any) {
// let {url, id} = res.json
// // replace www to notionID
// const {notionUser} = this.plugin.settings;
//
// if (notionUser !== "") {
// // replace url str "www" to notionID
// url = url.replace("www.notion.so", `${notionUser}.notion.site`)
// }
//
// await app.fileManager.processFrontMatter(nowFile, yamlContent => {
// if (yamlContent['notionID']) {
// delete yamlContent['notionID']
// }
// if (yamlContent['link']) {
// delete yamlContent['link']
// }
// // add new notionID and link
// yamlContent.notionID = id;
// yamlContent.link = url;
// });
//
// try {
// await navigator.clipboard.writeText(url)
// } catch (error) {
// new Notice(`复制链接失败,请手动复制${error}`)
// }
// // const __content = yamlContent.__content;
// // delete yamlContent.__content
// // const yamlhead = yaml.stringify(yamlContent)
// // // if yamlhead hava last \n remove it
// // const yamlhead_remove_n = yamlhead.replace(/\n$/, '')
// // // if __content have start \n remove it
// // const __content_remove_n = __content.replace(/^\n/, '')
// // const content = '---\n' +yamlhead_remove_n +'\n---\n' + __content_remove_n;
// // try {
// // await nowFile.vault.modify(nowFile, content)
// // } catch (error) {
// // new Notice(`write file error ${error}`)
// // }
// }
}

View File

@@ -1,269 +0,0 @@
import {App, Notice, TFile, requestUrl} from "obsidian";
import {markdownToBlocks} from "@jxpeng98/martian";
import * as yamlFrontMatter from "yaml-front-matter";
import MyPlugin from "src/main";
import {DatabaseDetails, PluginSettings} from "../../ui/settingTabs";
import {UploadBaseGeneral} from "./BaseUpload2NotionGeneral";
import {updateYamlInfo} from "../updateYaml";
import {i18nConfig} from "../../lang/I18n";
interface CreatePageResponse {
response: any;
data: any;
}
export class Upload2NotionGeneral extends UploadBaseGeneral {
settings: PluginSettings;
dbDetails: DatabaseDetails;
constructor(plugin: MyPlugin, dbDetails: DatabaseDetails) {
super(plugin, dbDetails);
this.dbDetails = dbDetails;
}
// 因为需要解析notion的block进行对比非常的麻烦
// 暂时就直接删除新建一个page
async updatePage(
notionID: string,
title: string,
cover: string,
tags: string[],
childArr: any,
) {
await this.deletePage(notionID);
const {databaseID} = this.dbDetails;
const databaseCover = await this.getDataBase(
databaseID,
);
if (cover == null) {
cover = databaseCover;
}
return await this.createPage(title, cover, tags, childArr);
}
async createPage(
title: string,
cover: string,
tags: string[],
childArr: any,
): Promise<CreatePageResponse> {
const {
databaseID,
customTitleButton,
customTitleName,
tagButton,
notionAPI
} = this.dbDetails;
// remove the annotations from the childArr if type is code block
childArr.forEach((block: any) => {
if (block.type === "code") {
block.code.rich_text.forEach((item: any) => {
if (item.type === "text" && item.annotations) {
delete item.annotations;
}
}
);
}
}
);
// check the length of the childArr and split it into chunks of 100
const childArrLength = childArr.length;
let extraArr: any[] = [];
let firstArr: any;
let pushCount = 0;
console.log(`Page includes ${childArrLength} blocks`)
if (childArrLength > 100) {
for (let i = 0; i < childArr.length; i += 100) {
if (i == 0) {
firstArr = childArr.slice(0, 100);
} else {
const chunk = childArr.slice(i, i + 100);
extraArr.push(chunk);
pushCount++;
}
}
} else {
firstArr = childArr;
}
const bodyString: any = {
parent: {
database_id: databaseID,
},
properties: {
[customTitleButton
? customTitleName
: "title"]: {
title: [
{
text: {
content: title,
},
},
],
},
...(tagButton
? {
tags: {
multi_select: tags && true ? tags.map((tag) => ({name: tag})) : [],
},
}
: {}),
},
children: firstArr,
};
if (cover) {
bodyString.cover = {
type: "external",
external: {
url: cover,
},
};
}
if (!bodyString.cover && this.plugin.settings.bannerUrl) {
bodyString.cover = {
type: "external",
external: {
url: this.plugin.settings.bannerUrl,
},
};
}
console.log(bodyString)
let response: any;
let data: any;
response = await requestUrl({
url: `https://api.notion.com/v1/pages`,
method: "POST",
headers: {
"Content-Type": "application/json",
// 'User-Agent': 'obsidian.md',
Authorization:
"Bearer " + notionAPI,
"Notion-Version": "2022-06-28",
},
body: JSON.stringify(bodyString),
throw: false
});
data = await response.json;
// console.log(data)
// console.log(response.status)
if (response.status !== 200) {
new Notice(`Error ${data.status}: ${data.code} \n ${i18nConfig["CheckConsole"]}`, 5000);
console.log(`Error message: \n ${data.message}`);
} else {
console.log(`Page created: ${data.url}`);
console.log(`Page ID: ${data.id}`);
}
//
// upload the rest of the blocks
if (pushCount > 0) {
for (let i = 0; i < pushCount; i++) {
const extraBlocks = {
children: extraArr[i],
};
console.log(extraBlocks)
const extraResponse = await requestUrl({
url: `https://api.notion.com/v1/blocks/${data.id}/children`,
method: "PATCH",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + notionAPI,
"Notion-Version": "2022-06-28",
},
body: JSON.stringify(extraBlocks),
});
const extraData: any = await extraResponse.json;
if (extraResponse.status !== 200) {
new Notice(`Error ${extraData.status}: ${extraData.code} \n ${i18nConfig["CheckConsole"]}`, 5000);
console.log(`Error message: \n ${extraData.message}`);
} else {
console.log(`${i18nConfig["ExtraBlockUploaded"]} to page: ${data.id}`);
if (i === pushCount - 1) {
console.log(`${i18nConfig["BlockUploaded"]} to page: ${data.id}`);
new Notice(`${i18nConfig["BlockUploaded"]} page: ${data.id}`, 5000);
}
}
}
}
return {
response,
data
}
}
async syncMarkdownToNotionGeneral(
title: string,
cover: string,
tags: string[],
markdown: string,
nowFile: TFile,
app: App,
): Promise<any> {
const options = {
notionLimits: {
truncate: false,
}
}
let res: any;
const yamlContent: any = yamlFrontMatter.loadFront(markdown);
const __content = yamlContent.__content;
const file2Block = markdownToBlocks(__content, options);
const frontMatter =
app.metadataCache.getFileCache(nowFile)?.frontmatter;
const {abName} = this.dbDetails
const notionIDKey = `NotionID-${abName}`;
const notionID = frontMatter ? frontMatter[notionIDKey] : null;
if (notionID) {
res = await this.updatePage(
notionID,
title,
cover,
tags,
file2Block,
);
} else {
res = await this.createPage(title, cover, tags, file2Block);
}
let {response, data} = res;
// console.log(response)
if (response && response.status === 200) {
await updateYamlInfo(
markdown,
nowFile,
data,
app,
this.plugin,
this.dbDetails,
);
}
return res;
}
}

View File

@@ -1,96 +0,0 @@
import { App, Notice, requestUrl, TFile } from "obsidian";
import { Client } from '@notionhq/client';
import { markdownToBlocks, } from "@jxpeng98/martian";
import * as yamlFrontMatter from "yaml-front-matter";
// import * as yaml from "yaml"
import MyPlugin from "src/main";
import { DatabaseDetails } from "../../ui/settingTabs";
export class UploadBaseNext {
plugin: MyPlugin;
notion: Client;
agent: any;
dbDetails: DatabaseDetails
constructor(plugin: MyPlugin, dbDetails: DatabaseDetails) {
this.plugin = plugin;
this.dbDetails = dbDetails
}
async deletePage(notionID: string) {
const { notionAPI } = this.dbDetails
return requestUrl({
url: `https://api.notion.com/v1/blocks/${notionID}`,
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + notionAPI,
'Notion-Version': '2022-06-28',
},
body: ''
});
}
async getDataBase(databaseID: string) {
const { notionAPI } = this.dbDetails
const response = await requestUrl({
url: `https://api.notion.com/v1/databases/${databaseID}`,
method: 'GET',
headers: {
'Authorization': 'Bearer ' + notionAPI,
'Notion-Version': '2022-06-28',
}
}
)
// Check if cover is present in the JSON response and then get the URL
if (response.json.cover && response.json.cover.external) {
return response.json.cover.external.url;
} else {
return null; // or some other default value, if you prefer
}
}
// async updateYamlInfo(yamlContent: string, nowFile: TFile, res: any, app: App, settings: any) {
// let {url, id} = res.json
// // replace www to notionID
// const { notionUser} = this.plugin.settings;
//
// if (notionUser !== "") {
// // replace url str "www" to notionID
// url = url.replace("www.notion.so", `${notionUser}.notion.site`)
// }
//
// await app.fileManager.processFrontMatter(nowFile, yamlContent => {
// if (yamlContent['notionID']) {
// delete yamlContent['notionID']
// }
// if (yamlContent['link']) {
// delete yamlContent['link']
// }
// // add new notionID and link
// yamlContent.notionID = id;
// yamlContent.link = url;
// });
//
// try {
// await navigator.clipboard.writeText(url)
// } catch (error) {
// new Notice(`复制链接失败,请手动复制${error}`)
// }
// // const __content = yamlContent.__content;
// // delete yamlContent.__content
// // const yamlhead = yaml.stringify(yamlContent)
// // // if yamlhead hava last \n remove it
// // const yamlhead_remove_n = yamlhead.replace(/\n$/, '')
// // // if __content have start \n remove it
// // const __content_remove_n = __content.replace(/^\n/, '')
// // const content = '---\n' +yamlhead_remove_n +'\n---\n' + __content_remove_n;
// // try {
// // await nowFile.vault.modify(nowFile, content)
// // } catch (error) {
// // new Notice(`write file error ${error}`)
// // }
// }
}

View File

@@ -1,420 +0,0 @@
import {UploadBaseNext} from "./BaseUpload2NotionNext";
import {App, Notice, TFile, requestUrl} from "obsidian";
import {markdownToBlocks} from "@jxpeng98/martian";
import * as yamlFrontMatter from "yaml-front-matter";
import MyPlugin from "src/main";
import {DatabaseDetails, PluginSettings} from "../../ui/settingTabs";
import {updateYamlInfo} from "../updateYaml";
import {LIMITS, paragraph} from "@jxpeng98/martian/src/notion";
import {i18nConfig} from "../../lang/I18n";
interface CreatePageResponse {
response: any;
data: any;
}
export class Upload2NotionNext extends UploadBaseNext {
settings: PluginSettings;
dbDetails: DatabaseDetails;
constructor(plugin: MyPlugin, dbDetails: DatabaseDetails) {
super(plugin, dbDetails);
this.dbDetails = dbDetails;
}
// 因为需要解析notion的block进行对比非常的麻烦
// 暂时就直接删除新建一个page
async updatePage(
notionID: string,
title: string,
emoji: string,
cover: string,
tags: string[],
type: string,
slug: string,
stats: string,
category: string,
summary: string,
paword: string,
favicon: string,
datetime: string,
childArr: any,
) {
await this.deletePage(notionID);
const {databaseID} = this.dbDetails;
const databaseCover = await this.getDataBase(databaseID);
if (cover == null) {
cover = databaseCover;
}
return await this.createPage(
title,
emoji,
cover,
tags,
type,
slug,
stats,
category,
summary,
paword,
favicon,
datetime,
childArr,
);
}
async createPage(
title: string,
emoji: string,
cover: string,
tags: string[],
type: string,
slug: string,
stats: string,
category: string,
summary: string,
pawrod: string,
favicon: string,
datetime: string,
childArr: any,
): Promise<CreatePageResponse> {
const {databaseID, notionAPI} = this.dbDetails;
// remove the annotations from the childArr if type is code block
childArr.forEach((block: any) => {
if (block.type === "code") {
block.code.rich_text.forEach((item: any) => {
if (item.type === "text" && item.annotations) {
delete item.annotations;
}
}
);
}
}
);
// check the length of the childArr
// if it is too long, split it into multiple pages
const childArrLength = childArr.length;
let extraArr: any[] = [];
let firstArr: any;
let pushCount = 0;
console.log(`Page includes ${childArrLength} blocks`)
if (childArrLength > 100) {
for (let i = 0; i < childArr.length; i += 100) {
if (i == 0) {
firstArr = childArr.slice(0, 100);
} else {
const chunk = childArr.slice(i, i + 100);
extraArr.push(chunk);
pushCount++;
}
}
} else {
firstArr = childArr;
}
const pageProperties: any = {
parent: {
database_id: databaseID,
},
properties: {
title: {
title: [
{
text: {
content: title,
},
},
],
},
type: {
select: {
name: type || "Post",
},
},
status: {
select: {
name: stats || "Draft",
},
},
category: {
select: {
name: category || "Obsidian",
},
},
password: {
rich_text: [
{
text: {
content: pawrod || "",
},
},
],
},
icon: {
rich_text: [
{
text: {
content: favicon || "",
},
},
],
},
date: {
date: {
start: datetime || new Date().toISOString(),
},
},
},
};
// add tags
if (tags) {
pageProperties.properties.tags = {
multi_select: tags.map((tag) => {
return {name: tag};
}),
};
}
// add title icon
if (emoji) {
pageProperties.icon = {
emoji: emoji,
};
}
// add slug
if (slug) {
pageProperties.properties.slug = {
rich_text: [
{
text: {
content: slug,
},
},
],
};
}
// check if summary is available
if (summary) {
pageProperties.properties.summary = {
rich_text: [
{
text: {
content: summary,
},
},
],
};
}
if (cover) {
pageProperties.cover = {
type: "external",
external: {
url: cover,
},
};
}
if (!pageProperties.cover && this.plugin.settings.bannerUrl) {
pageProperties.cover = {
type: "external",
external: {
url: this.plugin.settings.bannerUrl,
},
};
}
const bodyString: any = {
...pageProperties,
children: firstArr,
};
console.log(bodyString);
let response: any;
let data: any;
response = await requestUrl({
url: `https://api.notion.com/v1/pages`,
method: "POST",
headers: {
"Content-Type": "application/json",
// 'User-Agent': 'obsidian.md',
Authorization:
"Bearer " + notionAPI,
"Notion-Version": "2022-06-28",
},
body: JSON.stringify(bodyString),
throw: false
});
data = await response.json;
// console.log(data)
// console.log(response.status)
if (response.status !== 200) {
new Notice(`Error ${data.status}: ${data.code} \n ${i18nConfig["CheckConsole"]}`, 5000);
console.log(`Error message: \n ${data.message}`);
} else {
console.log(`Page created: ${data.url}`);
console.log(`Page ID: ${data.id}`);
}
//
// upload the rest of the blocks
if (pushCount > 0) {
for (let i = 0; i < pushCount; i++) {
const extraBlocks = {
children: extraArr[i],
};
console.log(extraBlocks)
const extraResponse = await requestUrl({
url: `https://api.notion.com/v1/blocks/${data.id}/children`,
method: "PATCH",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + notionAPI,
"Notion-Version": "2022-06-28",
},
body: JSON.stringify(extraBlocks),
});
const extraData: any = await extraResponse.json;
if (extraResponse.status !== 200) {
new Notice(`Error ${extraData.status}: ${extraData.code} \n ${i18nConfig["CheckConsole"]}`, 5000);
console.log(`Error message: \n ${extraData.message}`);
} else {
console.log(`${i18nConfig["ExtraBlockUploaded"]} to page: ${data.id}`);
if (i === pushCount - 1) {
console.log(`${i18nConfig["BlockUploaded"]} to page: ${data.id}`);
new Notice(`${i18nConfig["BlockUploaded"]} page: ${data.id}`, 5000);
}
}
}
}
return {
response,
data
};
}
async syncMarkdownToNotionNext(
title: string,
emoji: string,
cover: string,
tags: string[],
type: string,
slug: string,
stats: string,
category: string,
summary: string,
paword: string,
favicon: string,
datetime: string,
markdown: string,
nowFile: TFile,
app: App,
): Promise<any> {
const options = {
notionLimits: {
truncate: false,
},
};
let res: any;
const yamlContent: any = yamlFrontMatter.loadFront(markdown);
const __content = yamlContent.__content;
const file2Block = markdownToBlocks(__content, options);
const frontmatter =
app.metadataCache.getFileCache(nowFile)?.frontmatter;
const {abName} = this.dbDetails;
const notionIDKey = `NotionID-${abName}`;
const notionID = frontmatter ? frontmatter[notionIDKey] : null;
// increase the limits
// Motivated by https://github.com/tryfabric/martian/issues/51
file2Block.forEach((block, index) => {
if (
block.type === "paragraph" &&
block.paragraph.rich_text.length > LIMITS.RICH_TEXT_ARRAYS
) {
const newParagraphBlocks: any[] = [];
const chunk: any = [];
const richTextChunks = chunk(block.paragraph.rich_text, 100);
richTextChunks.forEach((chunk: any) => {
newParagraphBlocks.push(paragraph(chunk));
});
file2Block.splice(index, 1, ...newParagraphBlocks);
}
});
if (notionID) {
res = await this.updatePage(
notionID,
title,
emoji,
cover,
tags,
type,
slug,
stats,
category,
summary,
paword,
favicon,
datetime,
file2Block,
);
} else {
res = await this.createPage(
title,
emoji,
cover,
tags,
type,
slug,
stats,
category,
summary,
paword,
favicon,
datetime,
file2Block,
);
}
let {response, data} = res;
// console.log(response)
if (response && response.status === 200) {
await updateYamlInfo(
markdown,
nowFile,
data,
app,
this.plugin,
this.dbDetails,
);
}
return res;
}
}

View File

@@ -1,53 +0,0 @@
import { App, Notice, requestUrl, TFile } from "obsidian";
import { Client } from '@notionhq/client';
import { markdownToBlocks, } from "@jxpeng98/martian";
import * as yamlFrontMatter from "yaml-front-matter";
// import * as yaml from "yaml"
import MyPlugin from "src/main";
import { DatabaseDetails } from "../../ui/settingTabs";
export class UploadBaseCustom {
plugin: MyPlugin;
notion: Client;
agent: any;
dbDetails: DatabaseDetails
constructor(plugin: MyPlugin, dbDetails: DatabaseDetails) {
this.plugin = plugin;
this.dbDetails = dbDetails
}
async deletePage(notionID: string) {
const { notionAPI } = this.dbDetails
return requestUrl({
url: `https://api.notion.com/v1/blocks/${notionID}`,
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + notionAPI,
'Notion-Version': '2022-06-28',
},
body: ''
});
}
async getDataBase(databaseID: string) {
const { notionAPI } = this.dbDetails
const response = await requestUrl({
url: `https://api.notion.com/v1/databases/${databaseID}`,
method: 'GET',
headers: {
'Authorization': 'Bearer ' + notionAPI,
'Notion-Version': '2022-06-28',
}
}
)
// Check if cover is present in the JSON response and then get the URL
if (response.json.cover && response.json.cover.external) {
return response.json.cover.external.url;
} else {
return null; // or some other default value, if you prefer
}
}
}

View File

@@ -1,348 +0,0 @@
import {App, Notice, TFile, requestUrl} from "obsidian";
import {markdownToBlocks} from "@jxpeng98/martian";
import * as yamlFrontMatter from "yaml-front-matter";
import MyPlugin from "src/main";
import {DatabaseDetails, PluginSettings} from "../../ui/settingTabs";
import {updateYamlInfo} from "../updateYaml";
import {UploadBaseCustom} from "./BaseUpload2NotionCustom";
import {i18nConfig} from "../../lang/I18n";
interface CreatePageResponse {
response: any;
data: any;
}
export class Upload2NotionCustom extends UploadBaseCustom {
settings: PluginSettings;
dbDetails: DatabaseDetails;
constructor(plugin: MyPlugin, dbDetails: DatabaseDetails) {
super(plugin, dbDetails);
this.dbDetails = dbDetails;
}
// 因为需要解析notion的block进行对比非常的麻烦
// 暂时就直接删除新建一个page
async updatePage(
notionID: string,
cover: string,
customValues: Record<string, string>,
childArr: any,
) {
await this.deletePage(notionID);
const {databaseID} = this.dbDetails;
const databaseCover = await this.getDataBase(
databaseID
);
if (cover == null) {
cover = databaseCover;
}
return await this.createPage(cover, customValues, childArr);
}
async createPage(
cover: string,
customValues: Record<string, string>,
childArr: any,
): Promise<CreatePageResponse> {
const {
databaseID,
customProperties,
notionAPI
} = this.dbDetails;
// remove the annotations from the childArr if type is code block
childArr.forEach((block: any) => {
if (block.type === "code") {
block.code.rich_text.forEach((item: any) => {
if (item.type === "text" && item.annotations) {
delete item.annotations;
}
}
);
}
}
);
// check the length of the childArr and split it into chunks of 100
const childArrLength = childArr.length;
let extraArr: any[] = [];
let firstArr: any;
let pushCount = 0;
console.log(`Page includes ${childArrLength} blocks`)
if (childArrLength > 100) {
for (let i = 0; i < childArr.length; i += 100) {
if (i == 0) {
firstArr = childArr.slice(0, 100);
} else {
const chunk = childArr.slice(i, i + 100);
extraArr.push(chunk);
pushCount++;
}
}
} else {
firstArr = childArr;
}
const bodyString: any = this.buildBodyString(customProperties, customValues, firstArr);
if (cover) {
bodyString.cover = {
type: "external",
external: {
url: cover,
},
};
}
if (!bodyString.cover && this.plugin.settings.bannerUrl) {
bodyString.cover = {
type: "external",
external: {
url: this.plugin.settings.bannerUrl,
},
};
}
console.log(bodyString)
let response: any;
let data: any;
response = await requestUrl({
url: `https://api.notion.com/v1/pages`,
method: "POST",
headers: {
"Content-Type": "application/json",
// 'User-Agent': 'obsidian.md',
Authorization:
"Bearer " + notionAPI,
"Notion-Version": "2022-06-28",
},
body: JSON.stringify(bodyString),
throw: false
});
data = await response.json;
// console.log(data)
// console.log(response.status)
if (response.status !== 200) {
new Notice(`Error ${data.status}: ${data.code} \n ${i18nConfig["CheckConsole"]}`, 5000);
console.log(`Error message: \n ${data.message}`);
} else {
console.log(`Page created: ${data.url}`);
console.log(`Page ID: ${data.id}`);
}
//
// upload the rest of the blocks
if (pushCount > 0) {
for (let i = 0; i < pushCount; i++) {
const extraBlocks = {
children: extraArr[i],
};
console.log(extraBlocks)
const extraResponse = await requestUrl({
url: `https://api.notion.com/v1/blocks/${data.id}/children`,
method: "PATCH",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + notionAPI,
"Notion-Version": "2022-06-28",
},
body: JSON.stringify(extraBlocks),
});
const extraData: any = await extraResponse.json;
if (extraResponse.status !== 200) {
new Notice(`Error ${extraData.status}: ${extraData.code} \n ${i18nConfig["CheckConsole"]}`, 5000);
console.log(`Error message: \n ${extraData.message}`);
} else {
console.log(`${i18nConfig["ExtraBlockUploaded"]} to page: ${data.id}`);
if (i === pushCount - 1) {
console.log(`${i18nConfig["BlockUploaded"]} to page: ${data.id}`);
new Notice(`${i18nConfig["BlockUploaded"]} page: ${data.id}`, 5000);
}
}
}
}
return {
response, // for status code
data // for id and url
}
}
async syncMarkdownToNotionCustom(
cover: string,
customValues: Record<string, string>,
markdown: string,
nowFile: TFile,
app: App,
): Promise<any> {
const options = {
strictImageUrls: true,
notionLimits: {
truncate: false,
}
}
let res: any;
const yamlContent: any = yamlFrontMatter.loadFront(markdown);
const __content = yamlContent.__content;
const file2Block = markdownToBlocks(__content, options);
const frontMatter =
app.metadataCache.getFileCache(nowFile)?.frontmatter;
const {abName} = this.dbDetails
const notionIDKey = `NotionID-${abName}`;
const notionID = frontMatter ? frontMatter[notionIDKey] : null;
if (notionID) {
res = await this.updatePage(
notionID,
cover,
customValues,
file2Block,
);
} else {
res = await this.createPage(cover, customValues, file2Block);
}
let {response, data} = res;
// console.log(response)
if (response && response.status === 200) {
await updateYamlInfo(
markdown,
nowFile,
data,
app,
this.plugin,
this.dbDetails,
);
}
return res;
}
private buildPropertyObject(customName: string, customType: string, customValues: Record<string, any>) {
const value = customValues[customName] || '';
switch (customType) {
case "title":
return {
title: [
{
text: {
content: value,
},
},
],
};
case "rich_text":
return {
rich_text: [
{
text: {
content: value || '',
},
},
],
};
case "date":
return {
date: {
start: value || new Date().toISOString(),
},
};
case "number":
return {
number: Number(value),
};
case "phone_number":
return {
phone_number: value,
};
case "email":
return {
email: value,
};
case "url":
return {
url: value,
};
case "files":
return {
files: Array.isArray(value) ? value.map(url => ({
name: url,
type: "external",
external: {
url: url,
},
})) : [
{
name: value,
type: "external",
external: {
url: value,
},
},
],
};
case "checkbox":
return {
checkbox: Boolean(value) || false,
};
case "select":
return {
select: {
name: value,
},
};
case "multi_select":
return {
multi_select: Array.isArray(value) ? value.map(item => ({name: item})) : [{name: value}],
};
}
}
private buildBodyString(
customProperties: { customName: string; customType: string }[],
customValues: Record<string, string>,
childArr: any,
) {
const properties: { [key: string]: any } = {};
// Only include custom properties that have values
customProperties.forEach(({customName, customType}) => {
if (customValues[customName] !== undefined) {
properties[customName] = this.buildPropertyObject(customName, customType, customValues);
}
}
);
// console.log(properties)
return {
parent: {
database_id: this.dbDetails.databaseID,
},
properties,
children: childArr,
};
}
}