mirror of
https://github.com/zadam/trilium.git
synced 2025-11-11 15:55:52 +01:00
Merge branch 'main' into feat/note-map-filter
This commit is contained in:
@@ -42,5 +42,5 @@
|
||||
This will export the notes in an unencrypted form, so if you reimport into
|
||||
Trilium, make sure to re-protect these notes.</p>
|
||||
<h2>Supported syntax</h2>
|
||||
<p>See the dedicated page: <a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/mHbBMPDPkVV5/Oau6X9rCuegd/_help_rJ9grSgoExl9">Supported syntax</a>
|
||||
<p>See the dedicated page: <a class="reference-link" href="#root/_help_rJ9grSgoExl9">Supported syntax</a>
|
||||
</p>
|
||||
@@ -41,7 +41,7 @@
|
||||
Trilium-compatible syntax, but it will not export Trilium Notes into Markdown
|
||||
files with this syntax.</p>
|
||||
<aside class="admonition important">
|
||||
<p>The path to pages in wikilinks is resolved relatively to the <em>import root </em>and
|
||||
<p>The path to pages in wikilinks is resolved relatively to the <em>import root</em> and
|
||||
not the current directory of the note. This is to be inline with other
|
||||
platforms that use wikilinks such as SilverBullet.</p>
|
||||
<p>The root path of the import is determined as follows:</p>
|
||||
|
||||
@@ -62,4 +62,4 @@ class="image image-style-align-center">
|
||||
are currently no plans for adjusting it or allowing the user to customize
|
||||
them.</p>
|
||||
<h3>Markdown support</h3>
|
||||
<p>See <a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/mHbBMPDPkVV5/Oau6X9rCuegd/_help_rJ9grSgoExl9">Supported syntax</a>.</p>
|
||||
<p>See <a class="reference-link" href="#root/_help_rJ9grSgoExl9">Supported syntax</a>.</p>
|
||||
@@ -8,7 +8,7 @@ import appInfo from "../../services/app_info.js";
|
||||
* operationId: app-info
|
||||
* externalDocs:
|
||||
* description: Server implementation
|
||||
* url: https://github.com/TriliumNext/Notes/blob/v0.91.6/src/services/app_info.ts
|
||||
* url: https://github.com/TriliumNext/Trilium/blob/v0.91.6/src/services/app_info.ts
|
||||
* responses:
|
||||
* '200':
|
||||
* description: Installation info
|
||||
|
||||
@@ -25,7 +25,7 @@ import type { Request } from "express";
|
||||
* operationId: login-sync
|
||||
* externalDocs:
|
||||
* description: HMAC calculation
|
||||
* url: https://github.com/TriliumNext/Notes/blob/v0.91.6/src/services/utils.ts#L62-L66
|
||||
* url: https://github.com/TriliumNext/Trilium/blob/v0.91.6/src/services/utils.ts#L62-L66
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
|
||||
@@ -95,7 +95,7 @@ function forceFullSync() {
|
||||
* operationId: sync-changed
|
||||
* externalDocs:
|
||||
* description: Server implementation
|
||||
* url: https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/api/sync.ts
|
||||
* url: https://github.com/TriliumNext/Trilium/blob/v0.91.6/src/routes/api/sync.ts
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: instanceId
|
||||
@@ -214,7 +214,7 @@ const partialRequests: Record<
|
||||
* operationId: sync-update
|
||||
* externalDocs:
|
||||
* description: Server implementation
|
||||
* url: https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/api/sync.ts
|
||||
* url: https://github.com/TriliumNext/Trilium/blob/v0.91.6/src/routes/api/sync.ts
|
||||
* parameters:
|
||||
* - in: header
|
||||
* name: pageCount
|
||||
|
||||
@@ -136,7 +136,7 @@ function getNotesAndBranchesAndAttributes(_noteIds: string[] | Set<string>) {
|
||||
* operationId: tree
|
||||
* externalDocs:
|
||||
* description: Server implementation
|
||||
* url: https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/api/tree.ts
|
||||
* url: https://github.com/TriliumNext/Trilium/blob/v0.91.6/src/routes/api/tree.ts
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: subTreeNoteId
|
||||
|
||||
@@ -8,7 +8,7 @@ const doubleCsrfUtilities = doubleCsrf({
|
||||
path: "/",
|
||||
secure: false,
|
||||
sameSite: "strict",
|
||||
httpOnly: !isElectron // set to false for Electron, see https://github.com/TriliumNext/Notes/pull/966
|
||||
httpOnly: !isElectron // set to false for Electron, see https://github.com/TriliumNext/Trilium/pull/966
|
||||
},
|
||||
cookieName: "_csrf"
|
||||
});
|
||||
|
||||
@@ -77,7 +77,7 @@ function setPassword(req: Request, res: Response) {
|
||||
* operationId: login-normal
|
||||
* externalDocs:
|
||||
* description: HMAC calculation
|
||||
* url: https://github.com/TriliumNext/Notes/blob/v0.91.6/src/services/utils.ts#L62-L66
|
||||
* url: https://github.com/TriliumNext/Trilium/blob/v0.91.6/src/services/utils.ts#L62-L66
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/x-www-form-urlencoded:
|
||||
|
||||
@@ -255,8 +255,12 @@ export interface Api {
|
||||
/**
|
||||
* Returns week note for given date. If such a note doesn't exist, it is created.
|
||||
*
|
||||
* <p>
|
||||
* If the calendar does not support week notes, this method will return `null`.
|
||||
*
|
||||
* @param date in YYYY-MM-DD format
|
||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||
* @return an existing or newly created week note, or `null` if the calendar does not support week notes.
|
||||
*/
|
||||
getWeekNote(date: string, rootNote: BNote): BNote | null;
|
||||
|
||||
|
||||
@@ -293,25 +293,25 @@ describe("Markdown export", () => {
|
||||
const html = trimIndentation`\
|
||||
<ul>
|
||||
<li><a href="https://github.com/JYC333">@JYC333</a> made their first contribution
|
||||
in <a href="https://github.com/TriliumNext/Notes/pull/294">#294</a>
|
||||
in <a href="https://github.com/TriliumNext/Trilium/pull/294">#294</a>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://github.com/TriliumNext/Notes/issues/375">Note Tooltip isn't removed when clicking on internal trilium link in read-only mode</a>
|
||||
<p><a href="https://github.com/TriliumNext/Trilium/issues/375">Note Tooltip isn't removed when clicking on internal trilium link in read-only mode</a>
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://github.com/TriliumNext/Notes/issues/384">Calendar dropdown won't close if click/right-click other button that open notes from launcher bar</a>
|
||||
<p><a href="https://github.com/TriliumNext/Trilium/issues/384">Calendar dropdown won't close if click/right-click other button that open notes from launcher bar</a>
|
||||
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
`;
|
||||
const expected = trimIndentation`\
|
||||
* [@JYC333](https://github.com/JYC333) made their first contribution in [#294](https://github.com/TriliumNext/Notes/pull/294)
|
||||
* [Note Tooltip isn't removed when clicking on internal trilium link in read-only mode](https://github.com/TriliumNext/Notes/issues/375)
|
||||
* [Calendar dropdown won't close if click/right-click other button that open notes from launcher bar](https://github.com/TriliumNext/Notes/issues/384)`;
|
||||
* [@JYC333](https://github.com/JYC333) made their first contribution in [#294](https://github.com/TriliumNext/Trilium/pull/294)
|
||||
* [Note Tooltip isn't removed when clicking on internal trilium link in read-only mode](https://github.com/TriliumNext/Trilium/issues/375)
|
||||
* [Calendar dropdown won't close if click/right-click other button that open notes from launcher bar](https://github.com/TriliumNext/Trilium/issues/384)`;
|
||||
expect(markdownExportService.toMarkdown(html)).toBe(expected);
|
||||
});
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@ async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "h
|
||||
|
||||
function getDataFileName(type: string | null, mime: string, baseFileName: string, existingFileNames: Record<string, number>): string {
|
||||
let fileName = baseFileName.trim();
|
||||
if (!fileName) {
|
||||
fileName = "note";
|
||||
}
|
||||
|
||||
// Crop fileName to avoid its length exceeding 30 and prevent cutting into the extension.
|
||||
if (fileName.length > 30) {
|
||||
@@ -366,7 +369,7 @@ ${markdownContent}`;
|
||||
function saveNote(noteMeta: NoteMeta, filePathPrefix: string) {
|
||||
log.info(`Exporting note '${noteMeta.noteId}'`);
|
||||
|
||||
if (!noteMeta.noteId || !noteMeta.title) {
|
||||
if (!noteMeta.noteId || noteMeta.title === undefined) {
|
||||
throw new Error("Missing note meta.");
|
||||
}
|
||||
|
||||
@@ -515,97 +518,108 @@ ${markdownContent}`;
|
||||
archive.append(cssContent, { name: cssMeta.dataFileName });
|
||||
}
|
||||
|
||||
const existingFileNames: Record<string, number> = format === "html" ? { navigation: 0, index: 1 } : {};
|
||||
const rootMeta = createNoteMeta(branch, { notePath: [] }, existingFileNames);
|
||||
if (!rootMeta) {
|
||||
throw new Error("Unable to create root meta.");
|
||||
}
|
||||
try {
|
||||
const existingFileNames: Record<string, number> = format === "html" ? { navigation: 0, index: 1 } : {};
|
||||
const rootMeta = createNoteMeta(branch, { notePath: [] }, existingFileNames);
|
||||
if (!rootMeta) {
|
||||
throw new Error("Unable to create root meta.");
|
||||
}
|
||||
|
||||
const metaFile: NoteMetaFile = {
|
||||
formatVersion: 2,
|
||||
appVersion: packageInfo.version,
|
||||
files: [rootMeta]
|
||||
};
|
||||
|
||||
let navigationMeta: NoteMeta | null = null;
|
||||
let indexMeta: NoteMeta | null = null;
|
||||
let cssMeta: NoteMeta | null = null;
|
||||
|
||||
if (format === "html") {
|
||||
navigationMeta = {
|
||||
noImport: true,
|
||||
dataFileName: "navigation.html"
|
||||
const metaFile: NoteMetaFile = {
|
||||
formatVersion: 2,
|
||||
appVersion: packageInfo.version,
|
||||
files: [rootMeta]
|
||||
};
|
||||
|
||||
metaFile.files.push(navigationMeta);
|
||||
let navigationMeta: NoteMeta | null = null;
|
||||
let indexMeta: NoteMeta | null = null;
|
||||
let cssMeta: NoteMeta | null = null;
|
||||
|
||||
indexMeta = {
|
||||
noImport: true,
|
||||
dataFileName: "index.html"
|
||||
};
|
||||
if (format === "html") {
|
||||
navigationMeta = {
|
||||
noImport: true,
|
||||
dataFileName: "navigation.html"
|
||||
};
|
||||
|
||||
metaFile.files.push(indexMeta);
|
||||
metaFile.files.push(navigationMeta);
|
||||
|
||||
cssMeta = {
|
||||
noImport: true,
|
||||
dataFileName: "style.css"
|
||||
};
|
||||
indexMeta = {
|
||||
noImport: true,
|
||||
dataFileName: "index.html"
|
||||
};
|
||||
|
||||
metaFile.files.push(cssMeta);
|
||||
}
|
||||
metaFile.files.push(indexMeta);
|
||||
|
||||
for (const noteMeta of Object.values(noteIdToMeta)) {
|
||||
// filter out relations which are not inside this export
|
||||
noteMeta.attributes = (noteMeta.attributes || []).filter((attr) => {
|
||||
if (attr.type !== "relation") {
|
||||
return true;
|
||||
} else if (attr.value in noteIdToMeta) {
|
||||
return true;
|
||||
} else if (attr.value === "root" || attr.value?.startsWith("_")) {
|
||||
// relations to "named" noteIds can be preserved
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
cssMeta = {
|
||||
noImport: true,
|
||||
dataFileName: "style.css"
|
||||
};
|
||||
|
||||
metaFile.files.push(cssMeta);
|
||||
}
|
||||
|
||||
for (const noteMeta of Object.values(noteIdToMeta)) {
|
||||
// filter out relations which are not inside this export
|
||||
noteMeta.attributes = (noteMeta.attributes || []).filter((attr) => {
|
||||
if (attr.type !== "relation") {
|
||||
return true;
|
||||
} else if (attr.value in noteIdToMeta) {
|
||||
return true;
|
||||
} else if (attr.value === "root" || attr.value?.startsWith("_")) {
|
||||
// relations to "named" noteIds can be preserved
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!rootMeta) {
|
||||
// corner case of disabled export for exported note
|
||||
if ("sendStatus" in res) {
|
||||
res.sendStatus(400);
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const metaFileJson = JSON.stringify(metaFile, null, "\t");
|
||||
|
||||
archive.append(metaFileJson, { name: "!!!meta.json" });
|
||||
|
||||
saveNote(rootMeta, "");
|
||||
|
||||
if (format === "html") {
|
||||
if (!navigationMeta || !indexMeta || !cssMeta) {
|
||||
throw new Error("Missing meta.");
|
||||
}
|
||||
|
||||
saveNavigation(rootMeta, navigationMeta);
|
||||
saveIndex(rootMeta, indexMeta);
|
||||
saveCss(rootMeta, cssMeta);
|
||||
}
|
||||
|
||||
const note = branch.getNote();
|
||||
const zipFileName = `${branch.prefix ? `${branch.prefix} - ` : ""}${note.getTitleOrProtected() || "note"}.zip`;
|
||||
|
||||
if (setHeaders && "setHeader" in res) {
|
||||
res.setHeader("Content-Disposition", getContentDisposition(zipFileName));
|
||||
res.setHeader("Content-Type", "application/zip");
|
||||
}
|
||||
|
||||
archive.pipe(res);
|
||||
await archive.finalize();
|
||||
taskContext.taskSucceeded();
|
||||
} catch (e: unknown) {
|
||||
const message = `Export failed with error: ${e instanceof Error ? e.message : String(e)}`;
|
||||
log.error(message);
|
||||
taskContext.reportError(message);
|
||||
|
||||
if (!rootMeta) {
|
||||
// corner case of disabled export for exported note
|
||||
if ("sendStatus" in res) {
|
||||
res.sendStatus(400);
|
||||
res.removeHeader("Content-Disposition");
|
||||
res.removeHeader("Content-Type");
|
||||
res.status(500).send(message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const metaFileJson = JSON.stringify(metaFile, null, "\t");
|
||||
|
||||
archive.append(metaFileJson, { name: "!!!meta.json" });
|
||||
|
||||
saveNote(rootMeta, "");
|
||||
|
||||
if (format === "html") {
|
||||
if (!navigationMeta || !indexMeta || !cssMeta) {
|
||||
throw new Error("Missing meta.");
|
||||
}
|
||||
|
||||
saveNavigation(rootMeta, navigationMeta);
|
||||
saveIndex(rootMeta, indexMeta);
|
||||
saveCss(rootMeta, cssMeta);
|
||||
}
|
||||
|
||||
const note = branch.getNote();
|
||||
const zipFileName = `${branch.prefix ? `${branch.prefix} - ` : ""}${note.getTitleOrProtected()}.zip`;
|
||||
|
||||
if (setHeaders && "setHeader" in res) {
|
||||
res.setHeader("Content-Disposition", getContentDisposition(zipFileName));
|
||||
res.setHeader("Content-Type", "application/zip");
|
||||
}
|
||||
|
||||
archive.pipe(res);
|
||||
await archive.finalize();
|
||||
|
||||
taskContext.taskSucceeded();
|
||||
}
|
||||
|
||||
async function exportToZipFile(noteId: string, format: "markdown" | "html", zipFilePath: string, zipExportOptions?: AdvancedExportOptions) {
|
||||
|
||||
@@ -84,7 +84,7 @@ export const DEFAULT_ALLOWED_TAGS = [
|
||||
"del",
|
||||
"ins",
|
||||
"en-media", // for ENEX import
|
||||
// Additional tags (https://github.com/TriliumNext/Notes/issues/567)
|
||||
// Additional tags (https://github.com/TriliumNext/Trilium/issues/567)
|
||||
"acronym",
|
||||
"article",
|
||||
"big",
|
||||
|
||||
@@ -259,15 +259,15 @@ $$`;
|
||||
const input = trimIndentation`\
|
||||
### 🐞 Bugfixes
|
||||
|
||||
* [v0.90.4 docker does not read USER\_UID and USER\_GID from environment](https://github.com/TriliumNext/Notes/issues/331)
|
||||
* [Invalid CSRF token on Android phone](https://github.com/TriliumNext/Notes/issues/318)
|
||||
* [Excess spacing in lists](https://github.com/TriliumNext/Notes/issues/341)`;
|
||||
* [v0.90.4 docker does not read USER\_UID and USER\_GID from environment](https://github.com/TriliumNext/Trilium/issues/331)
|
||||
* [Invalid CSRF token on Android phone](https://github.com/TriliumNext/Trilium/issues/318)
|
||||
* [Excess spacing in lists](https://github.com/TriliumNext/Trilium/issues/341)`;
|
||||
const expected = [
|
||||
/*html*/`<h3>🐞 Bugfixes</h3>`,
|
||||
/*html*/`<ul>`,
|
||||
/*html*/`<li><a href="https://github.com/TriliumNext/Notes/issues/331">v0.90.4 docker does not read USER_UID and USER_GID from environment</a></li>`,
|
||||
/*html*/`<li><a href="https://github.com/TriliumNext/Notes/issues/318">Invalid CSRF token on Android phone</a></li>`,
|
||||
/*html*/`<li><a href="https://github.com/TriliumNext/Notes/issues/341">Excess spacing in lists</a></li>`,
|
||||
/*html*/`<li><a href="https://github.com/TriliumNext/Trilium/issues/331">v0.90.4 docker does not read USER_UID and USER_GID from environment</a></li>`,
|
||||
/*html*/`<li><a href="https://github.com/TriliumNext/Trilium/issues/318">Invalid CSRF token on Android phone</a></li>`,
|
||||
/*html*/`<li><a href="https://github.com/TriliumNext/Trilium/issues/341">Excess spacing in lists</a></li>`,
|
||||
/*html*/`</ul>`
|
||||
].join("");
|
||||
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
||||
|
||||
Reference in New Issue
Block a user