diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 28d45245d..7d893979a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,6 +11,14 @@ concurrency: cancel-in-progress: true jobs: + sanity-check: + name: Sanity Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Check version consistency + run: pnpm tsx ${{ github.workspace }}/scripts/check-version-consistency.ts ${{ github.ref_name }} make-electron: name: Make Electron strategy: diff --git a/apps/build-docs/package.json b/apps/build-docs/package.json index ef5a0053b..68c7544f7 100644 --- a/apps/build-docs/package.json +++ b/apps/build-docs/package.json @@ -9,7 +9,7 @@ "keywords": [], "author": "Elian Doran ", "license": "AGPL-3.0-only", - "packageManager": "pnpm@10.27.0", + "packageManager": "pnpm@10.28.0", "devDependencies": { "@redocly/cli": "2.14.3", "archiver": "7.0.1", diff --git a/apps/client/package.json b/apps/client/package.json index 57628fd37..a76b75b3b 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,6 +1,6 @@ { "name": "@triliumnext/client", - "version": "0.101.1", + "version": "0.101.3", "description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)", "private": true, "license": "AGPL-3.0-only", diff --git a/apps/client/src/components/app_context.ts b/apps/client/src/components/app_context.ts index 560a00438..b5f203b24 100644 --- a/apps/client/src/components/app_context.ts +++ b/apps/client/src/components/app_context.ts @@ -154,6 +154,7 @@ export type CommandMappings = { }; openInTab: ContextMenuCommandData; openNoteInSplit: ContextMenuCommandData; + openNoteInWindow: ContextMenuCommandData; openNoteInPopup: ContextMenuCommandData; toggleNoteHoisting: ContextMenuCommandData; insertNoteAfter: ContextMenuCommandData; diff --git a/apps/client/src/entities/fnote.ts b/apps/client/src/entities/fnote.ts index 048d175db..83255e488 100644 --- a/apps/client/src/entities/fnote.ts +++ b/apps/client/src/entities/fnote.ts @@ -616,7 +616,9 @@ export default class FNote { } isFolder() { - return this.type === "search" || this.getFilteredChildBranches().length > 0; + if (this.isLabelTruthy("subtreeHidden")) return false; + if (this.type === "search") return true; + return this.getFilteredChildBranches().length > 0; } getFilteredChildBranches() { diff --git a/apps/client/src/menus/tree_context_menu.ts b/apps/client/src/menus/tree_context_menu.ts index 51f9912b3..8dca18d90 100644 --- a/apps/client/src/menus/tree_context_menu.ts +++ b/apps/client/src/menus/tree_context_menu.ts @@ -1,21 +1,21 @@ -import NoteColorPicker from "./custom-items/NoteColorPicker.jsx"; -import treeService from "../services/tree.js"; -import froca from "../services/froca.js"; -import clipboard from "../services/clipboard.js"; -import noteCreateService from "../services/note_create.js"; -import contextMenu, { type MenuCommandItem, type MenuItem } from "./context_menu.js"; import appContext, { type ContextMenuCommandData, type FilteredCommandNames } from "../components/app_context.js"; +import type { SelectMenuItemEventListener } from "../components/events.js"; +import type FAttachment from "../entities/fattachment.js"; +import attributes from "../services/attributes.js"; +import { executeBulkActions } from "../services/bulk_action.js"; +import clipboard from "../services/clipboard.js"; +import dialogService from "../services/dialog.js"; +import froca from "../services/froca.js"; +import { t } from "../services/i18n.js"; +import noteCreateService from "../services/note_create.js"; import noteTypesService from "../services/note_types.js"; import server from "../services/server.js"; import toastService from "../services/toast.js"; -import dialogService from "../services/dialog.js"; -import { t } from "../services/i18n.js"; -import type NoteTreeWidget from "../widgets/note_tree.js"; -import type FAttachment from "../entities/fattachment.js"; -import type { SelectMenuItemEventListener } from "../components/events.js"; +import treeService from "../services/tree.js"; import utils from "../services/utils.js"; -import attributes from "../services/attributes.js"; -import { executeBulkActions } from "../services/bulk_action.js"; +import type NoteTreeWidget from "../widgets/note_tree.js"; +import contextMenu, { type MenuCommandItem, type MenuItem } from "./context_menu.js"; +import NoteColorPicker from "./custom-items/NoteColorPicker.jsx"; // TODO: Deduplicate once client/server is well split. interface ConvertToAttachmentResponse { @@ -72,6 +72,8 @@ export default class TreeContextMenu implements SelectMenuItemEventListener | null)[] = [ { title: t("tree-context-menu.open-in-a-new-tab"), command: "openInTab", shortcut: "Ctrl+Click", uiIcon: "bx bx-link-external", enabled: noSelectedNotes }, { title: t("tree-context-menu.open-in-a-new-split"), command: "openNoteInSplit", uiIcon: "bx bx-dock-right", enabled: noSelectedNotes }, + { title: t("tree-context-menu.open-in-a-new-window"), command: "openNoteInWindow", uiIcon: "bx bx-window-open", enabled: noSelectedNotes }, { title: t("tree-context-menu.open-in-popup"), command: "openNoteInPopup", uiIcon: "bx bx-edit", enabled: noSelectedNotes }, isHoisted ? null : { - title: `${t("tree-context-menu.hoist-note")}`, - command: "toggleNoteHoisting", - keyboardShortcut: "toggleNoteHoisting", - uiIcon: "bx bxs-chevrons-up", - enabled: noSelectedNotes && notSearch - }, + title: `${t("tree-context-menu.hoist-note")}`, + command: "toggleNoteHoisting", + keyboardShortcut: "toggleNoteHoisting", + uiIcon: "bx bxs-chevrons-up", + enabled: noSelectedNotes && notSearch + }, !isHoisted || !isNotRoot ? null : { title: t("tree-context-menu.unhoist-note"), command: "toggleNoteHoisting", keyboardShortcut: "toggleNoteHoisting", uiIcon: "bx bx-door-open" }, @@ -112,7 +115,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener { + const note = await froca.getNote(this.node.data.noteId); + if (!note) return; + attributes.setBooleanWithInheritance(note, "subtreeHidden", !hasSubtreeHidden); + } + }, { title: t("tree-context-menu.sort-by"), command: "sortChildNotes", @@ -164,7 +176,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener[] }, { kind: "separator" }, @@ -292,25 +304,30 @@ export default class TreeContextMenu implements SelectMenuItemEventListener(command, { node: this.node, - notePath: notePath, + notePath, noteId: this.node.data.noteId, selectedOrActiveBranchIds: this.treeWidget.getSelectedOrActiveBranchIds(this.node), selectedOrActiveNoteIds: this.treeWidget.getSelectedOrActiveNoteIds(this.node) diff --git a/apps/client/src/services/attributes.spec.ts b/apps/client/src/services/attributes.spec.ts new file mode 100644 index 000000000..724f53a36 --- /dev/null +++ b/apps/client/src/services/attributes.spec.ts @@ -0,0 +1,139 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { buildNote } from "../test/easy-froca"; +import { setBooleanWithInheritance } from "./attributes"; +import froca from "./froca"; +import server from "./server.js"; + +// Spy on server methods to track calls +// @ts-expect-error the generic typing is causing issues here +server.put = vi.fn(async (url: string, data?: T) => ({} as T)); +// @ts-expect-error the generic typing is causing issues here +server.remove = vi.fn(async (url: string) => ({} as T)); + +describe("Set boolean with inheritance", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("doesn't call server if value matches directly", async () => { + const noteWithLabel = buildNote({ + title: "New note", + "#foo": "" + }); + const noteWithoutLabel = buildNote({ + title: "New note" + }); + + await setBooleanWithInheritance(noteWithLabel, "foo", true); + await setBooleanWithInheritance(noteWithoutLabel, "foo", false); + expect(server.put).not.toHaveBeenCalled(); + expect(server.remove).not.toHaveBeenCalled(); + }); + + it("sets boolean normally without inheritance", async () => { + const standaloneNote = buildNote({ + title: "New note" + }); + + await setBooleanWithInheritance(standaloneNote, "foo", true); + expect(server.put).toHaveBeenCalledWith(`notes/${standaloneNote.noteId}/set-attribute`, { + type: "label", + name: "foo", + value: "", + isInheritable: false + }); + }); + + it("removes boolean normally without inheritance", async () => { + const standaloneNote = buildNote({ + title: "New note", + "#foo": "" + }); + + const attributeId = standaloneNote.getLabel("foo")!.attributeId; + await setBooleanWithInheritance(standaloneNote, "foo", false); + expect(server.remove).toHaveBeenCalledWith(`notes/${standaloneNote.noteId}/attributes/${attributeId}`); + }); + + it("doesn't call server if value matches inherited", async () => { + const parentNote = buildNote({ + title: "Parent note", + "#foo(inheritable)": "", + "children": [ + { + title: "Child note" + } + ] + }); + const childNote = froca.getNoteFromCache(parentNote.children[0])!; + expect(childNote.isLabelTruthy("foo")).toBe(true); + await setBooleanWithInheritance(childNote, "foo", true); + expect(server.put).not.toHaveBeenCalled(); + expect(server.remove).not.toHaveBeenCalled(); + }); + + it("overrides boolean with inheritance", async () => { + const parentNote = buildNote({ + title: "Parent note", + "#foo(inheritable)": "", + "children": [ + { + title: "Child note" + } + ] + }); + const childNote = froca.getNoteFromCache(parentNote.children[0])!; + expect(childNote.isLabelTruthy("foo")).toBe(true); + await setBooleanWithInheritance(childNote, "foo", false); + expect(server.put).toHaveBeenCalledWith(`notes/${childNote.noteId}/set-attribute`, { + type: "label", + name: "foo", + value: "false", + isInheritable: false + }); + }); + + it("overrides boolean with inherited false", async () => { + const parentNote = buildNote({ + title: "Parent note", + "#foo(inheritable)": "false", + "children": [ + { + title: "Child note" + } + ] + }); + const childNote = froca.getNoteFromCache(parentNote.children[0])!; + expect(childNote.isLabelTruthy("foo")).toBe(false); + await setBooleanWithInheritance(childNote, "foo", true); + expect(server.put).toHaveBeenCalledWith(`notes/${childNote.noteId}/set-attribute`, { + type: "label", + name: "foo", + value: "", + isInheritable: false + }); + }); + + it("deletes override boolean with inherited false with already existing value", async () => { + const parentNote = buildNote({ + title: "Parent note", + "#foo(inheritable)": "false", + "children": [ + { + title: "Child note", + "#foo": "false", + } + ] + }); + const childNote = froca.getNoteFromCache(parentNote.children[0])!; + expect(childNote.isLabelTruthy("foo")).toBe(false); + await setBooleanWithInheritance(childNote, "foo", true); + expect(server.put).toBeCalledWith(`notes/${childNote.noteId}/set-attribute`, { + type: "label", + name: "foo", + value: "", + isInheritable: false + }); + }); +}); diff --git a/apps/client/src/services/attributes.ts b/apps/client/src/services/attributes.ts index 4559c8f8b..0b156dcf3 100644 --- a/apps/client/src/services/attributes.ts +++ b/apps/client/src/services/attributes.ts @@ -1,14 +1,15 @@ -import server from "./server.js"; -import froca from "./froca.js"; -import type FNote from "../entities/fnote.js"; -import type { AttributeRow } from "./load_results.js"; import { AttributeType } from "@triliumnext/commons"; +import type FNote from "../entities/fnote.js"; +import froca from "./froca.js"; +import type { AttributeRow } from "./load_results.js"; +import server from "./server.js"; + async function addLabel(noteId: string, name: string, value: string = "", isInheritable = false) { await server.put(`notes/${noteId}/attribute`, { type: "label", - name: name, - value: value, + name, + value, isInheritable }); } @@ -16,8 +17,8 @@ async function addLabel(noteId: string, name: string, value: string = "", isInhe export async function setLabel(noteId: string, name: string, value: string = "", isInheritable = false) { await server.put(`notes/${noteId}/set-attribute`, { type: "label", - name: name, - value: value, + name, + value, isInheritable }); } @@ -25,12 +26,42 @@ export async function setLabel(noteId: string, name: string, value: string = "", export async function setRelation(noteId: string, name: string, value: string = "", isInheritable = false) { await server.put(`notes/${noteId}/set-attribute`, { type: "relation", - name: name, - value: value, + name, + value, isInheritable }); } +/** + * Sets a boolean label on the given note, taking inheritance into account. If the desired value matches the inherited + * value, any owned label will be removed to allow the inherited value to take effect. If the desired value differs + * from the inherited value, an owned label will be created or updated to reflect the desired value. + * + * When checking if the boolean value is set, don't use `note.hasLabel`; instead use `note.isLabelTruthy`. + * + * @param note the note on which to set the boolean label. + * @param labelName the name of the label to set. + * @param value the boolean value to set for the label. + */ +export async function setBooleanWithInheritance(note: FNote, labelName: string, value: boolean) { + const actualValue = note.isLabelTruthy(labelName); + if (actualValue === value) return; + const hasInheritedValue = !note.hasOwnedLabel(labelName) && note.hasLabel(labelName); + + if (hasInheritedValue) { + if (value) { + setLabel(note.noteId, labelName, ""); + } else { + // Label is inherited - override to false. + setLabel(note.noteId, labelName, "false"); + } + } else if (value) { + setLabel(note.noteId, labelName, ""); + } else { + removeOwnedLabelByName(note, labelName); + } +} + async function removeAttributeById(noteId: string, attributeId: string) { await server.remove(`notes/${noteId}/attributes/${attributeId}`); } @@ -142,6 +173,7 @@ export default { setLabel, setRelation, setAttribute, + setBooleanWithInheritance, removeAttributeById, removeOwnedLabelByName, removeOwnedRelationByName, diff --git a/apps/client/src/services/branches.ts b/apps/client/src/services/branches.ts index e5a5158e1..cd1f5c6e7 100644 --- a/apps/client/src/services/branches.ts +++ b/apps/client/src/services/branches.ts @@ -1,12 +1,12 @@ -import utils from "./utils.js"; -import server from "./server.js"; -import toastService, { type ToastOptionsWithRequiredId } from "./toast.js"; +import appContext from "../components/app_context.js"; +import type { ResolveOptions } from "../widgets/dialogs/delete_notes.js"; import froca from "./froca.js"; import hoistedNoteService from "./hoisted_note.js"; -import ws from "./ws.js"; -import appContext from "../components/app_context.js"; import { t } from "./i18n.js"; -import type { ResolveOptions } from "../widgets/dialogs/delete_notes.js"; +import server from "./server.js"; +import toastService, { type ToastOptionsWithRequiredId } from "./toast.js"; +import utils from "./utils.js"; +import ws from "./ws.js"; // TODO: Deduplicate type with server interface Response { @@ -66,7 +66,7 @@ async function moveAfterBranch(branchIdsToMove: string[], afterBranchId: string) } } -async function moveToParentNote(branchIdsToMove: string[], newParentBranchId: string) { +async function moveToParentNote(branchIdsToMove: string[], newParentBranchId: string, componentId?: string) { const newParentBranch = froca.getBranch(newParentBranchId); if (!newParentBranch) { return; @@ -86,7 +86,7 @@ async function moveToParentNote(branchIdsToMove: string[], newParentBranchId: st continue; } - const resp = await server.put(`branches/${branchIdToMove}/move-to/${newParentBranchId}`); + const resp = await server.put(`branches/${branchIdToMove}/move-to/${newParentBranchId}`, undefined, componentId); if (!resp.success) { toastService.showError(resp.message); diff --git a/apps/client/src/services/content_renderer.ts b/apps/client/src/services/content_renderer.ts index 7137efae7..4fbf51024 100644 --- a/apps/client/src/services/content_renderer.ts +++ b/apps/client/src/services/content_renderer.ts @@ -23,6 +23,12 @@ export interface RenderOptions { imageHasZoom?: boolean; /** If enabled, it will prevent the default behavior in which an empty note would display a list of children. */ noChildrenList?: boolean; + /** If enabled, it will prevent rendering of included notes. */ + noIncludedNotes?: boolean; + /** If enabled, it will include archived notes when rendering children list. */ + includeArchivedNotes?: boolean; + /** Set of note IDs that have already been seen during rendering to prevent infinite recursion. */ + seenNoteIds?: Set; } const CODE_MIME_TYPES = new Set(["application/json"]); diff --git a/apps/client/src/services/content_renderer_text.spec.ts b/apps/client/src/services/content_renderer_text.spec.ts new file mode 100644 index 000000000..4199965cc --- /dev/null +++ b/apps/client/src/services/content_renderer_text.spec.ts @@ -0,0 +1,132 @@ +import { trimIndentation } from "@triliumnext/commons"; +import { describe, expect, it } from "vitest"; + +import { buildNote } from "../test/easy-froca"; +import renderText from "./content_renderer_text"; + +describe("Text content renderer", () => { + it("renders included note", async () => { + const contentEl = document.createElement("div"); + const includedNote = buildNote({ + title: "Included note", + content: "

This is the included note.

" + }); + const note = buildNote({ + title: "New note", + content: trimIndentation` +

+ Hi there +

+
+   +
+ ` + }); + await renderText(note, $(contentEl)); + expect(contentEl.querySelectorAll("section.include-note").length).toBe(1); + expect(contentEl.querySelectorAll("section.include-note p").length).toBe(1); + }); + + it("skips rendering included note", async () => { + const contentEl = document.createElement("div"); + const includedNote = buildNote({ + title: "Included note", + content: "

This is the included note.

" + }); + const note = buildNote({ + title: "New note", + content: trimIndentation` +

+ Hi there +

+
+   +
+ ` + }); + await renderText(note, $(contentEl), { noIncludedNotes: true }); + expect(contentEl.querySelectorAll("section.include-note").length).toBe(0); + }); + + it("doesn't enter infinite loop on direct recursion", async () => { + const contentEl = document.createElement("div"); + const note = buildNote({ + title: "New note", + id: "Y7mBwmRjQyb4", + content: trimIndentation` +

+ Hi there +

+
+   +
+
+   +
+ ` + }); + await renderText(note, $(contentEl)); + expect(contentEl.querySelectorAll("section.include-note").length).toBe(0); + }); + + it("doesn't enter infinite loop on indirect recursion", async () => { + const contentEl = document.createElement("div"); + buildNote({ + id: "first", + title: "Included note", + content: trimIndentation`\ +

This is the included note.

+
+   +
+ ` + }); + const note = buildNote({ + id: "second", + title: "New note", + content: trimIndentation` +

+ Hi there +

+
+   +
+ ` + }); + await renderText(note, $(contentEl)); + expect(contentEl.querySelectorAll("section.include-note").length).toBe(1); + }); + + it("renders children list when note is empty", async () => { + const contentEl = document.createElement("div"); + const parentNote = buildNote({ + title: "Parent note", + children: [ + { title: "Child note 1" }, + { title: "Child note 2" } + ] + }); + await renderText(parentNote, $(contentEl)); + const items = contentEl.querySelectorAll("a"); + expect(items.length).toBe(2); + expect(items[0].textContent).toBe("Child note 1"); + expect(items[1].textContent).toBe("Child note 2"); + }); + + it("skips archived notes in children list", async () => { + const contentEl = document.createElement("div"); + const parentNote = buildNote({ + title: "Parent note", + children: [ + { title: "Child note 1" }, + { title: "Child note 2", "#archived": "" }, + { title: "Child note 3" } + ] + }); + await renderText(parentNote, $(contentEl)); + const items = contentEl.querySelectorAll("a"); + expect(items.length).toBe(2); + expect(items[0].textContent).toBe("Child note 1"); + expect(items[1].textContent).toBe("Child note 3"); + }); +}); diff --git a/apps/client/src/services/content_renderer_text.ts b/apps/client/src/services/content_renderer_text.ts index 5b388d64e..e72f9e178 100644 --- a/apps/client/src/services/content_renderer_text.ts +++ b/apps/client/src/services/content_renderer_text.ts @@ -15,7 +15,14 @@ export default async function renderText(note: FNote | FAttachment, $renderedCon if (blob && !isHtmlEmpty(blob.content)) { $renderedContent.append($('
').html(blob.content)); - await renderIncludedNotes($renderedContent[0]); + + const seenNoteIds = options.seenNoteIds ?? new Set(); + seenNoteIds.add("noteId" in note ? note.noteId : note.attachmentId); + if (!options.noIncludedNotes) { + await renderIncludedNotes($renderedContent[0], seenNoteIds); + } else { + $renderedContent.find("section.include-note").remove(); + } if ($renderedContent.find("span.math-tex").length > 0) { renderMathInElement($renderedContent[0], { trust: true }); @@ -35,11 +42,11 @@ export default async function renderText(note: FNote | FAttachment, $renderedCon await rewriteMermaidDiagramsInContainer($renderedContent[0] as HTMLDivElement); await formatCodeBlocks($renderedContent); } else if (note instanceof FNote && !options.noChildrenList) { - await renderChildrenList($renderedContent, note); + await renderChildrenList($renderedContent, note, options.includeArchivedNotes ?? false); } } -async function renderIncludedNotes(contentEl: HTMLElement) { +async function renderIncludedNotes(contentEl: HTMLElement, seenNoteIds: Set) { // TODO: Consider duplicating with server's share/content_renderer.ts. const includeNoteEls = contentEl.querySelectorAll("section.include-note"); @@ -66,7 +73,15 @@ async function renderIncludedNotes(contentEl: HTMLElement) { continue; } - const renderedContent = (await content_renderer.getRenderedContent(note)).$renderedContent; + if (seenNoteIds.has(noteId)) { + console.warn(`Skipping inclusion of ${noteId} to avoid circular reference.`); + includeNoteEl.remove(); + continue; + } + + const renderedContent = (await content_renderer.getRenderedContent(note, { + seenNoteIds + })).$renderedContent; includeNoteEl.replaceChildren(...renderedContent); } } @@ -98,7 +113,7 @@ export async function applyInlineMermaid(container: HTMLDivElement) { } } -async function renderChildrenList($renderedContent: JQuery, note: FNote) { +async function renderChildrenList($renderedContent: JQuery, note: FNote, includeArchivedNotes: boolean) { let childNoteIds = note.getChildNoteIds(); if (!childNoteIds.length) { @@ -108,14 +123,16 @@ async function renderChildrenList($renderedContent: JQuery, note: F $renderedContent.css("padding", "10px"); $renderedContent.addClass("text-with-ellipsis"); + // just load the first 10 child notes if (childNoteIds.length > 10) { childNoteIds = childNoteIds.slice(0, 10); } - // just load the first 10 child notes const childNotes = await froca.getNotes(childNoteIds); for (const childNote of childNotes) { + if (childNote.isArchived && !includeArchivedNotes) continue; + $renderedContent.append( await link.createLink(`${note.noteId}/${childNote.noteId}`, { showTooltip: false, diff --git a/apps/client/src/services/load_results.ts b/apps/client/src/services/load_results.ts index 899560de4..b5706705b 100644 --- a/apps/client/src/services/load_results.ts +++ b/apps/client/src/services/load_results.ts @@ -1,4 +1,5 @@ import type { AttachmentRow, EtapiTokenRow, NoteType, OptionNames } from "@triliumnext/commons"; + import type { AttributeType } from "../entities/fattribute.js"; import type { EntityChange } from "../server_types.js"; @@ -135,7 +136,14 @@ export default class LoadResults { } getBranchRows() { - return this.branchRows.map((row) => this.getEntityRow("branches", row.branchId)).filter((branch) => !!branch); + return this.branchRows.map((row) => { + const branch = this.getEntityRow("branches", row.branchId); + if (branch) { + // Merge the componentId from the tracked row with the entity data + return { ...branch, componentId: row.componentId }; + } + return null; + }).filter((branch) => !!branch) as BranchRow[]; } addNoteReordering(parentNoteId: string, componentId: string) { @@ -153,7 +161,14 @@ export default class LoadResults { getAttributeRows(componentId = "none"): AttributeRow[] { return this.attributeRows .filter((row) => row.componentId !== componentId) - .map((row) => this.getEntityRow("attributes", row.attributeId)) + .map((row) => { + const attr = this.getEntityRow("attributes", row.attributeId); + if (attr) { + // Merge the componentId from the tracked row with the entity data + return { ...attr, componentId: row.componentId }; + } + return null; + }) .filter((attr) => !!attr) as AttributeRow[]; } diff --git a/apps/client/src/test/easy-froca.ts b/apps/client/src/test/easy-froca.ts index 59d4c2e4a..d3ae75718 100644 --- a/apps/client/src/test/easy-froca.ts +++ b/apps/client/src/test/easy-froca.ts @@ -69,24 +69,6 @@ export function buildNote(noteDef: NoteDefinition) { }); note.getBlob = async () => blob; - // Manage children. - if (noteDef.children) { - for (const childDef of noteDef.children) { - const childNote = buildNote(childDef); - const branchId = `${note.noteId}_${childNote.noteId}`; - const branch = new FBranch(froca, { - branchId, - noteId: childNote.noteId, - parentNoteId: note.noteId, - notePosition: childNotePosition, - fromSearchNote: false - }); - froca.branches[branchId] = branch; - note.addChild(childNote.noteId, branchId, false); - childNotePosition += 10; - } - } - let position = 0; for (const [ key, value ] of Object.entries(noteDef)) { const attributeId = utils.randomString(12); @@ -136,5 +118,25 @@ export function buildNote(noteDef: NoteDefinition) { } noteAttributeCache.attributes[note.noteId].push(attribute); } + + // Manage children. + if (noteDef.children) { + for (const childDef of noteDef.children) { + const childNote = buildNote(childDef); + const branchId = `${note.noteId}_${childNote.noteId}`; + const branch = new FBranch(froca, { + branchId, + noteId: childNote.noteId, + parentNoteId: note.noteId, + notePosition: childNotePosition, + fromSearchNote: false + }); + froca.branches[branchId] = branch; + note.addChild(childNote.noteId, branchId, false); + childNote.addParent(note.noteId, branchId, false); + childNotePosition += 10; + } + } + return note; } diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 457f01eb6..652ad0725 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -800,7 +800,8 @@ "geo-map": "Geo Map", "board": "Board", "presentation": "Presentation", - "include_archived_notes": "Show archived notes" + "include_archived_notes": "Show archived notes", + "hide_child_notes": "Hide child notes in tree" }, "edited_notes": { "no_edited_notes_found": "No edited notes on this day yet...", @@ -1643,6 +1644,7 @@ "tree-context-menu": { "open-in-a-new-tab": "Open in a new tab", "open-in-a-new-split": "Open in a new split", + "open-in-a-new-window": "Open in a new window", "insert-note-after": "Insert note after", "insert-child-note": "Insert child note", "archive": "Archive", @@ -1655,6 +1657,8 @@ "advanced": "Advanced", "expand-subtree": "Expand subtree", "collapse-subtree": "Collapse subtree", + "hide-subtree": "Hide subtree", + "show-subtree": "Show subtree", "sort-by": "Sort by...", "recent-changes-in-subtree": "Recent changes in subtree", "convert-to-attachment": "Convert to attachment", @@ -1772,7 +1776,12 @@ "clone-indicator-tooltip": "This note has {{- count}} parents: {{- parents}}", "clone-indicator-tooltip-single": "This note is cloned (1 additional parent: {{- parent}})", "shared-indicator-tooltip": "This note is shared publicly", - "shared-indicator-tooltip-with-url": "This note is shared publicly at: {{- url}}" + "shared-indicator-tooltip-with-url": "This note is shared publicly at: {{- url}}", + "subtree-hidden-tooltip_one": "{{count}} child note that is hidden from the tree", + "subtree-hidden-tooltip_other": "{{count}} child notes that are hidden from the tree", + "subtree-hidden-moved-title": "Added to {{title}}", + "subtree-hidden-moved-description-collection": "This collection hides its child notes in the tree.", + "subtree-hidden-moved-description-other": "Child notes are hidden in the tree for this note." }, "title_bar_buttons": { "window-on-top": "Keep Window on Top" diff --git a/apps/client/src/translations/es/translation.json b/apps/client/src/translations/es/translation.json index 252cce17f..7e0ae3c69 100644 --- a/apps/client/src/translations/es/translation.json +++ b/apps/client/src/translations/es/translation.json @@ -21,7 +21,13 @@ }, "bundle-error": { "title": "Hubo un fallo al cargar un script personalizado", - "message": "El script de la nota con ID \"{{id}}\", titulado \"{{title}}\" no pudo ser ejecutado debido a:\n\n{{message}}" + "message": "El script no pudo ser ejecutado debido a:\n\n{{message}}" + }, + "widget-list-error": { + "title": "Hubo un fallo al obtener la lista de widgets del servidor" + }, + "widget-render-error": { + "title": "Hubo un fallo al renderizar un widget personalizado de React" } }, "add_link": { @@ -691,7 +697,7 @@ "convert_into_attachment_successful": "La nota '{{title}}' ha sido convertida a un archivo adjunto.", "convert_into_attachment_prompt": "¿Está seguro que desea convertir la nota '{{title}}' en un archivo adjunto de la nota padre?", "print_pdf": "Exportar como PDF...", - "open_note_on_server": "Abrir nota en el servidor" + "open_note_on_server": "Abrir nota en servidor" }, "onclick_button": { "no_click_handler": "El widget de botón '{{componentId}}' no tiene un controlador de clics definido" @@ -737,7 +743,7 @@ "zpetne_odkazy": { "relation": "relación", "backlink_one": "{{count}} Vínculo de retroceso", - "backlink_many": "", + "backlink_many": "{{count}} Vínculos de retroceso", "backlink_other": "{{count}} vínculos de retroceso" }, "mobile_detail_menu": { @@ -750,7 +756,10 @@ "note_icon": { "change_note_icon": "Cambiar icono de nota", "search": "Búsqueda:", - "reset-default": "Restablecer a icono por defecto" + "reset-default": "Restablecer a icono por defecto", + "search_placeholder_one": "Buscar {{number}} icono a través de {{count}} paquetes", + "search_placeholder_many": "Buscar {{number}} iconos a través de {{count}} paquetes", + "search_placeholder_other": "Buscar {{number}} iconos a través de {{count}} paquetes" }, "basic_properties": { "note_type": "Tipo de nota", @@ -790,7 +799,7 @@ "file_type": "Tipo de archivo", "file_size": "Tamaño del archivo", "download": "Descargar", - "open": "Abrir", + "open": "Abrir externamente", "upload_new_revision": "Subir nueva revisión", "upload_success": "Se ha subido una nueva revisión de archivo.", "upload_failed": "Error al cargar una nueva revisión de archivo.", @@ -1303,11 +1312,11 @@ "code_mime_types": { "title": "Tipos MIME disponibles en el menú desplegable", "tooltip_syntax_highlighting": "Resaltado de sintaxis", - "tooltip_code_block_syntax": "Bloques de código en notas de texto", - "tooltip_code_note_syntax": "Notas de código" + "tooltip_code_block_syntax": "Bloques de Código en notas de Texto", + "tooltip_code_note_syntax": "Notas de Código" }, "vim_key_bindings": { - "use_vim_keybindings_in_code_notes": "Atajos de teclas de Vim", + "use_vim_keybindings_in_code_notes": "Combinaciones de teclas Vim", "enable_vim_keybindings": "Habilitar los atajos de teclas de Vim en la notas de código (no es modo ex)" }, "wrap_lines": { @@ -1572,7 +1581,7 @@ "will_be_deleted_in": "Este archivo adjunto se eliminará automáticamente en {{time}}", "will_be_deleted_soon": "Este archivo adjunto se eliminará automáticamente pronto", "deletion_reason": ", porque el archivo adjunto no está vinculado en el contenido de la nota. Para evitar la eliminación, vuelva a agregar el enlace del archivo adjunto al contenido o convierta el archivo adjunto en una nota.", - "role_and_size": "Rol: {{role}}, Tamaño: {{size}}", + "role_and_size": "Rol: {{role}}, tamaño: {{size}}, MIME: {{- mimeType}}", "link_copied": "Enlace del archivo adjunto copiado al portapapeles.", "unrecognized_role": "Rol de archivo adjunto no reconocido '{{role}}'." }, @@ -1623,7 +1632,7 @@ "import-into-note": "Importar a nota", "apply-bulk-actions": "Aplicar acciones en lote", "converted-to-attachments": "{{count}} notas han sido convertidas en archivos adjuntos.", - "convert-to-attachment-confirm": "¿Está seguro que desea convertir las notas seleccionadas en archivos adjuntos de sus notas padres?", + "convert-to-attachment-confirm": "¿Está seguro que desea convertir las notas seleccionadas en archivos adjuntos de sus notas padres? Esta operación solo aplica a notas de Imagen, otras notas serán omitidas.", "open-in-popup": "Edición rápida", "archive": "Archivar", "unarchive": "Desarchivar" @@ -1718,7 +1727,10 @@ "note_detail": { "could_not_find_typewidget": "No se pudo encontrar typeWidget para el tipo '{{type}}'", "printing": "Impresión en curso...", - "printing_pdf": "Exportando a PDF en curso.." + "printing_pdf": "Exportando a PDF en curso..", + "print_report_collection_content_one": "{{count}} nota en la colección no se puede imprimir porque no son compatibles o está protegida.", + "print_report_collection_content_many": "{{count}} notas en la colección no se pueden imprimir porque no son compatibles o están protegidas.", + "print_report_collection_content_other": "{{count}} notas en la colección no se pueden imprimir porque no son compatibles o están protegidas." }, "note_title": { "placeholder": "escriba el título de la nota aquí..." @@ -1930,7 +1942,7 @@ "unknown_widget": "Widget desconocido para \"{{id}}\"." }, "note_language": { - "not_set": "No establecido", + "not_set": "Idioma no establecido", "configure-languages": "Configurar idiomas..." }, "content_language": { @@ -1969,7 +1981,7 @@ "hide-weekends": "Ocultar fines de semana", "show-scale": "Mostrar escala", "display-week-numbers": "Mostrar números de semana", - "map-style": "Estilo de mapa:", + "map-style": "Estilo de mapa", "max-nesting-depth": "Máxima profundidad de anidamiento:", "vector_light": "Vector (claro)", "vector_dark": "Vector (oscuro)", @@ -2098,5 +2110,36 @@ "clear-color": "Borrar color de nota", "set-color": "Asignar color de nota", "set-custom-color": "Asignar color de nota personalizado" + }, + "status_bar": { + "backlinks_one": "{{count}} vínculo de retroceso", + "backlinks_many": "{{count}} vínculos de retroceso", + "backlinks_other": "{{count}} vínculos de retroceso", + "backlinks_title_one": "Ver vínculo de retroceso", + "backlinks_title_many": "Ver vínculos de retroceso", + "backlinks_title_other": "Ver vínculos de retroceso", + "attachments_one": "{{count}} adjunto", + "attachments_many": "{{count}} adjuntos", + "attachments_other": "{{count}} adjuntos", + "attachments_title_one": "Ver adjunto en una nueva pestaña", + "attachments_title_many": "Ver adjuntos en una nueva pestaña", + "attachments_title_other": "Ver adjuntos en una nueva pestaña", + "attributes_one": "{{count}} atributo", + "attributes_many": "{{count}} atributos", + "attributes_other": "{{count}} atributos", + "note_paths_one": "{{count}} ruta", + "note_paths_many": "{{count}} rutas", + "note_paths_other": "{{count}} rutas" + }, + "pdf": { + "attachments_one": "{{count}} adjunto", + "attachments_many": "{{count}} adjuntos", + "attachments_other": "{{count}} adjuntos", + "layers_one": "{{count}} capa", + "layers_many": "{{count}} capas", + "layers_other": "{{count}} capas", + "pages_one": "{{count}} página", + "pages_many": "{{count}} páginas", + "pages_other": "{{count}} páginas" } } diff --git a/apps/client/src/types-fancytree.d.ts b/apps/client/src/types-fancytree.d.ts index cb709ea07..a8a151b55 100644 --- a/apps/client/src/types-fancytree.d.ts +++ b/apps/client/src/types-fancytree.d.ts @@ -69,7 +69,7 @@ declare namespace Fancytree { debug(msg: any): void; /** Expand (or collapse) all parent nodes. */ - expandAll(flag?: boolean, options?: Object): void; + expandAll(flag?: boolean, options?: object): void; /** [ext-filter] Dimm or hide whole branches. * @returns {integer} count @@ -221,6 +221,7 @@ declare namespace Fancytree { branchId: string; isProtected: boolean; noteType: NoteType; + subtreeHidden: boolean; } interface FancytreeNewNode extends FancytreeNodeData { @@ -369,7 +370,7 @@ declare namespace Fancytree { * @param mode 'before', 'after', or 'child' (default='child') * @param init NodeData (or simple title string) */ - editCreateNode(mode?: string, init?: Object): void; + editCreateNode(mode?: string, init?: object): void; /** [ext-edit] Stop inline editing. * @@ -526,7 +527,7 @@ declare namespace Fancytree { * * @param opts passed to `setExpanded()`. Defaults to {noAnimation: false, noEvents: false, scrollIntoView: true} */ - makeVisible(opts?: Object): JQueryPromise; + makeVisible(opts?: object): JQueryPromise; /** Move this node to targetNode. * @@ -589,25 +590,25 @@ declare namespace Fancytree { * @param effects animation options. * @param options {topNode: null, effects: ..., parent: ...} this node will remain visible in any case, even if `this` is outside the scroll pane. */ - scrollIntoView(effects?: boolean, options?: Object): JQueryPromise; + scrollIntoView(effects?: boolean, options?: object): JQueryPromise; /** * @param effects animation options. * @param options {topNode: null, effects: ..., parent: ...} this node will remain visible in any case, even if `this` is outside the scroll pane. */ - scrollIntoView(effects?: Object, options?: Object): JQueryPromise; + scrollIntoView(effects?: object, options?: object): JQueryPromise; /** * @param flag pass false to deactivate * @param opts additional options. Defaults to {noEvents: false} */ - setActive(flag?: boolean, opts?: Object): JQueryPromise; + setActive(flag?: boolean, opts?: object): JQueryPromise; /** * @param flag pass false to collapse. * @param opts additional options. Defaults to {noAnimation:false, noEvents:false} */ - setExpanded(flag?: boolean, opts?: Object): JQueryPromise; + setExpanded(flag?: boolean, opts?: object): JQueryPromise; /** * Set keyboard focus to this node. @@ -1109,7 +1110,7 @@ declare namespace Fancytree { /** class names added to the node markup (separate with space) */ extraClasses?: string | undefined; /** all properties from will be copied to `node.data` */ - data?: Object | undefined; + data?: object | undefined; /** Will be added as title attribute of the node's icon span,thus enabling a tooltip. */ iconTooltip?: string | undefined; @@ -1160,7 +1161,7 @@ declare namespace Fancytree { escapeHtml(s: string): string; - getEventTarget(event: Event): Object; + getEventTarget(event: Event): object; getEventTargetType(event: Event): string; @@ -1179,7 +1180,7 @@ declare namespace Fancytree { parseHtml($ul: JQuery): NodeData[]; /** Add Fancytree extension definition to the list of globally available extensions. */ - registerExtension(definition: Object): void; + registerExtension(definition: object): void; unescapeHtml(s: string): string; diff --git a/apps/client/src/widgets/NoteDetail.tsx b/apps/client/src/widgets/NoteDetail.tsx index c2f212044..ef9d68c99 100644 --- a/apps/client/src/widgets/NoteDetail.tsx +++ b/apps/client/src/widgets/NoteDetail.tsx @@ -215,7 +215,7 @@ export default function NoteDetail() { return (
{Object.entries(noteTypesToRender).map(([ itemType, Element ]) => { return ) { const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); const { pageNotes, ...pagination } = usePagination(note, noteIds); + const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived"); return (
@@ -52,7 +53,7 @@ export function GridView({ note, noteIds: unfilteredNoteIds, highlightedTokens } @@ -94,14 +95,16 @@ function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expan {isExpanded && <> - + }
); } -function GridNoteCard({ note, parentNote, highlightedTokens }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined }) { +function GridNoteCard({ note, parentNote, highlightedTokens, includeArchived }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined, includeArchived: boolean }) { + const titleRef = useRef(null); + const [ noteTitle, setNoteTitle ] = useState(); const notePath = getNotePath(parentNote, note); return ( @@ -120,6 +123,7 @@ function GridNoteCard({ note, parentNote, highlightedTokens }: { note: FNote, pa note={note} trim highlightedTokens={highlightedTokens} + includeArchivedNotes={includeArchived} />
); @@ -136,14 +140,22 @@ function NoteAttributes({ note }: { note: FNote }) { return ; } -function NoteContent({ note, trim, noChildrenList, highlightedTokens }: { note: FNote, trim?: boolean, noChildrenList?: boolean, highlightedTokens: string[] | null | undefined }) { +function NoteContent({ note, trim, noChildrenList, highlightedTokens, includeArchivedNotes }: { + note: FNote; + trim?: boolean; + noChildrenList?: boolean; + highlightedTokens: string[] | null | undefined; + includeArchivedNotes: boolean; +}) { const contentRef = useRef(null); const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens); useEffect(() => { content_renderer.getRenderedContent(note, { trim, - noChildrenList + noChildrenList, + noIncludedNotes: true, + includeArchivedNotes }) .then(({ $renderedContent, type }) => { if (!contentRef.current) return; diff --git a/apps/client/src/widgets/launch_bar/LauncherContainer.tsx b/apps/client/src/widgets/launch_bar/LauncherContainer.tsx index 26a502a8a..3450a4c01 100644 --- a/apps/client/src/widgets/launch_bar/LauncherContainer.tsx +++ b/apps/client/src/widgets/launch_bar/LauncherContainer.tsx @@ -1,17 +1,18 @@ import { useCallback, useLayoutEffect, useState } from "preact/hooks"; + import FNote from "../../entities/fnote"; import froca from "../../services/froca"; import { isDesktop, isMobile } from "../../services/utils"; -import CalendarWidget from "./CalendarWidget"; -import SpacerWidget from "./SpacerWidget"; -import BookmarkButtons from "./BookmarkButtons"; -import ProtectedSessionStatusWidget from "./ProtectedSessionStatusWidget"; -import SyncStatus from "./SyncStatus"; -import HistoryNavigationButton from "./HistoryNavigation"; -import { AiChatButton, CommandButton, CustomWidget, NoteLauncher, QuickSearchLauncherWidget, ScriptLauncher, TodayLauncher } from "./LauncherDefinitions"; import { useTriliumEvent } from "../react/hooks"; import { onWheelHorizontalScroll } from "../widget_utils"; +import BookmarkButtons from "./BookmarkButtons"; +import CalendarWidget from "./CalendarWidget"; +import HistoryNavigationButton from "./HistoryNavigation"; import { LaunchBarContext } from "./launch_bar_widgets"; +import { AiChatButton, CommandButton, CustomWidget, NoteLauncher, QuickSearchLauncherWidget, ScriptLauncher, TodayLauncher } from "./LauncherDefinitions"; +import ProtectedSessionStatusWidget from "./ProtectedSessionStatusWidget"; +import SpacerWidget from "./SpacerWidget"; +import SyncStatus from "./SyncStatus"; export default function LauncherContainer({ isHorizontalLayout }: { isHorizontalLayout: boolean }) { const childNotes = useLauncherChildNotes(); @@ -34,18 +35,19 @@ export default function LauncherContainer({ isHorizontalLayout }: { isHorizontal }}> {childNotes?.map(childNote => { if (childNote.type !== "launcher") { - throw new Error(`Note '${childNote.noteId}' '${childNote.title}' is not a launcher even though it's in the launcher subtree`); + console.warn(`Note '${childNote.noteId}' '${childNote.title}' is not a launcher even though it's in the launcher subtree`); + return false; } if (!isDesktop() && childNote.isLabelTruthy("desktopOnly")) { return false; } - return + return ; })}
- ) + ); } function Launcher({ note, isHorizontalLayout }: { note: FNote, isHorizontalLayout: boolean }) { @@ -72,7 +74,7 @@ function initBuiltinWidget(note: FNote, isHorizontalLayout: boolean) { const builtinWidget = note.getLabelValue("builtinWidget"); switch (builtinWidget) { case "calendar": - return + return ; case "spacer": // || has to be inside since 0 is a valid value const baseSize = parseInt(note.getLabelValue("baseSize") || "40"); @@ -86,15 +88,15 @@ function initBuiltinWidget(note: FNote, isHorizontalLayout: boolean) { case "syncStatus": return ; case "backInHistoryButton": - return + return ; case "forwardInHistoryButton": - return + return ; case "todayInJournal": - return + return ; case "quickSearch": - return + return ; case "aiChatLauncher": - return + return ; default: throw new Error(`Unrecognized builtin widget ${builtinWidget} for launcher ${note.noteId} "${note.title}"`); } diff --git a/apps/client/src/widgets/note_bars/CollectionProperties.tsx b/apps/client/src/widgets/note_bars/CollectionProperties.tsx index 6fc510fc7..d5c9ffb42 100644 --- a/apps/client/src/widgets/note_bars/CollectionProperties.tsx +++ b/apps/client/src/widgets/note_bars/CollectionProperties.tsx @@ -82,6 +82,13 @@ function ViewOptions({ note, viewType }: { note: FNote, viewType: ViewTypeOption ))} {properties.length > 0 && } + + void = (e) => e.stopPropagation(); +const cancelClickPropagation: (e: Event) => void = (e) => e.stopPropagation(); // TODO: Fix once we remove Node.js API from public type Timeout = NodeJS.Timeout | string | number | undefined; @@ -190,6 +190,9 @@ export interface DragData { export const TREE_CLIPBOARD_TYPE = "application/x-fancytree-node"; +/** Entity changes below the given threshold will be processed without batching to avoid performance degradation. */ +const BATCH_UPDATE_THRESHOLD = 10; + export default class NoteTreeWidget extends NoteContextAwareWidget { private $tree!: JQuery; private $treeActions!: JQuery; @@ -201,6 +204,8 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { private treeName: "main"; private autoCollapseTimeoutId?: Timeout; private lastFilteredHoistedNotePath?: string | null; + private spotlightedNotePath?: string | null; + private spotlightedNode: Fancytree.FancytreeNode | null = null; private tree!: Fancytree.Fancytree; constructor() { @@ -353,6 +358,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { this.$tree.fancytree({ titlesTabbable: true, keyboard: true, + toggleEffect: options.is("motionEnabled") ? undefined : false, extensions: ["dnd5", "clones", "filter"], source: treeData, scrollOfs: { @@ -552,7 +558,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { } else if (data.hitMode === "after") { branchService.moveAfterBranch(selectedBranchIds, node.data.branchId); } else if (data.hitMode === "over") { - branchService.moveToParentNote(selectedBranchIds, node.data.branchId); + branchService.moveToParentNote(selectedBranchIds, node.data.branchId, this.componentId); } else { throw new Error(`Unknown hitMode '${data.hitMode}'`); } @@ -598,102 +604,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { clones: { highlightActiveClones: true }, - async enhanceTitle ( - event: Event, - data: { - node: Fancytree.FancytreeNode; - noteId: string; - } - ) { - const node = data.node; - - if (!node.data.noteId) { - // if there's "non-note" node, then don't enhance - // this can happen for e.g. "Load error!" node - return; - } - - const note = await froca.getNote(node.data.noteId, true); - - if (!note) { - return; - } - - const activeNoteContext = appContext.tabManager.getActiveContext(); - - const $span = $(node.span); - - $span.find(".tree-item-button").remove(); - $span.find(".note-indicator-icon").remove(); - - const isHoistedNote = activeNoteContext && activeNoteContext.hoistedNoteId === note.noteId && note.noteId !== "root"; - - if (note.hasLabel("workspace") && !isHoistedNote) { - const $enterWorkspaceButton = $(``).on( - "click", - cancelClickPropagation - ); - - $span.append($enterWorkspaceButton); - } - - if (note.type === "search") { - const $refreshSearchButton = $(``).on( - "click", - cancelClickPropagation - ); - - $span.append($refreshSearchButton); - } - - // TODO: Deduplicate with server's notes.ts#getAndValidateParent - if (!["search", "launcher"].includes(note.type) - && !note.isOptions() - && !note.isLaunchBarConfig() - && !note.noteId.startsWith("_help") - ) { - const $createChildNoteButton = $(``).on( - "click", - cancelClickPropagation - ); - - $span.append($createChildNoteButton); - } - - if (isHoistedNote) { - const $unhoistButton = $(``).on("click", cancelClickPropagation); - - $span.append($unhoistButton); - } - - // Add clone indicator with tooltip if note has multiple parents - const parentNotes = note.getParentNotes(); - const realParents = parentNotes.filter( - (parent) => !["_share", "_lbBookmarks"].includes(parent.noteId) && parent.type !== "search" - ); - - if (realParents.length > 1) { - const parentTitles = realParents.map((p) => p.title).join(", "); - const tooltipText = realParents.length === 2 - ? t("note_tree.clone-indicator-tooltip-single", { parent: realParents[1].title }) - : t("note_tree.clone-indicator-tooltip", { count: realParents.length, parents: parentTitles }); - - const $cloneIndicator = $(``); - $cloneIndicator.attr("title", tooltipText); - $span.find(".fancytree-title").append($cloneIndicator); - } - - // Add shared indicator with tooltip if note is shared - if (note.isShared()) { - const shareId = note.getOwnedLabelValue("shareAlias") || note.noteId; - const shareUrl = `${location.origin}${location.pathname}share/${shareId}`; - const tooltipText = t("note_tree.shared-indicator-tooltip-with-url", { url: shareUrl }); - - const $sharedIndicator = $(``); - $sharedIndicator.attr("title", tooltipText); - $span.find(".fancytree-title").append($sharedIndicator); - } - }, + enhanceTitle: buildEnhanceTitle(), // this is done to automatically lazy load all expanded notes after tree load loadChildren: (event, data) => { data.node.visit((subNode) => { @@ -803,6 +714,23 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { childBranches = childBranches.slice(0, MAX_SEARCH_RESULTS_IN_TREE); } + if (parentNote.isLabelTruthy("subtreeHidden")) { + // If we have a spotlighted note path, show only the child that leads to it + if (this.spotlightedNotePath) { + const spotlightPathSegments = this.spotlightedNotePath.split('/'); + const parentIndex = spotlightPathSegments.indexOf(parentNote.noteId); + + if (parentIndex >= 0 && parentIndex < spotlightPathSegments.length - 1) { + const nextNoteIdInPath = spotlightPathSegments[parentIndex + 1]; + childBranches = childBranches.filter(branch => branch.noteId === nextNoteIdInPath); + } else { + childBranches = []; + } + } else { + childBranches = []; + } + } + for (const branch of childBranches) { if (hideArchivedNotes) { const note = branch.getNoteFromCache(); @@ -874,6 +802,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { lazy: true, folder: isFolder, expanded: !!branch.isExpanded && note.type !== "search", + subtreeHidden: note.isLabelTruthy("subtreeHidden"), key: utils.randomString(12) // this should prevent some "duplicate key" errors }; @@ -932,6 +861,10 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { extraClasses.push(...["tinted", colorClass]); } + if (this.spotlightedNotePath && this.spotlightedNotePath.endsWith(`/${note.noteId}`)) { + extraClasses.push("spotlighted-node"); + } + return extraClasses.join(" "); } @@ -1082,18 +1015,43 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { foundChildNode = this.findChildNode(parentNode, childNoteId); if (!foundChildNode) { - if (logErrors) { - // besides real errors, this can be also caused by hiding of e.g. included images - // these are real notes with real notePath, user can display them in a detail, - // but they don't have a node in the tree + const childNote = await froca.getNote(childNoteId); - const childNote = await froca.getNote(childNoteId); + if (childNote?.type === "image") return; - if (!childNote || childNote.type !== "image") { - ws.logError( - `Can't find node for child node of noteId=${childNoteId} for parent of noteId=${parentNode.data.noteId} and hoistedNoteId=${hoistedNoteService.getHoistedNoteId()}, requested path is ${notePath}` - ); + // The child note can be part of a note with #subtreeHidden, case in which we need to "spotlight" it. + const parentNote = froca.getNoteFromCache(parentNode.data.noteId); + if (parentNote?.isLabelTruthy("subtreeHidden")) { + // Enable spotlight mode and reload the parent to show only the path to this note + this.spotlightedNotePath = notePath; + await parentNode.load(true); + + // Try to find the child again after reload + foundChildNode = this.findChildNode(parentNode, childNoteId); + this.spotlightedNode = foundChildNode ?? null; + + if (!foundChildNode) { + if (logErrors || !childNote) { + ws.logError( + `Can't find node for child node of noteId=${childNoteId} for parent of noteId=${parentNode.data.noteId} and hoistedNoteId=${hoistedNoteService.getHoistedNoteId()}, requested path is ${notePath}` + ); + return; + } + return; } + + parentNode = foundChildNode; + continue; + } + + // besides real errors, this can be also caused by hiding of e.g. included images + // these are real notes with real notePath, user can display them in a detail, + // but they don't have a node in the tree + if (logErrors || !childNote) { + ws.logError( + `Can't find node for child node of noteId=${childNoteId} for parent of noteId=${parentNode.data.noteId} and hoistedNoteId=${hoistedNoteService.getHoistedNoteId()}, requested path is ${notePath}` + ); + return; } return; @@ -1108,7 +1066,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { } findChildNode(parentNode: Fancytree.FancytreeNode, childNoteId: string) { - return parentNode.getChildren().find((childNode) => childNode.data.noteId === childNoteId); + return parentNode.getChildren()?.find((childNode) => childNode.data.noteId === childNoteId); } async expandToNote(notePath: string, logErrors = true) { @@ -1149,12 +1107,20 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { (!treeService.isNotePathInHiddenSubtree(this.noteContext.notePath) || (await hoistedNoteService.isHoistedInHiddenSubtree())) && (await this.getNodeFromPath(this.noteContext.notePath)); + if (this.spotlightedNode && newActiveNode !== this.spotlightedNode) { + // Can get removed when switching to another note in a spotlighted subtree. + if (this.spotlightedNode.parent) { + this.spotlightedNode.remove(); + } + this.spotlightedNode = null; + this.spotlightedNotePath = null; + } + if (newActiveNode !== oldActiveNode) { let oldActiveNodeFocused = false; if (oldActiveNode) { oldActiveNodeFocused = oldActiveNode.hasFocus(); - oldActiveNode.setActive(false); oldActiveNode.setFocus(false); } @@ -1257,10 +1223,18 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { const { movedActiveNode, parentsOfAddedNodes } = await this.#processBranchRows(branchRows, refreshCtx); for (const noteId of loadResults.getNoteIds()) { + const contentReloaded = loadResults.isNoteContentReloaded(noteId); + if (contentReloaded && !loadResults.isNoteReloaded(noteId, contentReloaded.componentId)) { + // Only the note content was reloaded, not the note itself. This would cause a redundant update on every few seconds while editing a note. + continue; + } + refreshCtx.noteIdsToUpdate.add(noteId); } - await this.#executeTreeUpdates(refreshCtx, loadResults); + if (refreshCtx.noteIdsToUpdate.size + refreshCtx.noteIdsToReload.size > 0) { + await this.#executeTreeUpdates(refreshCtx, loadResults); + } await this.#setActiveNode(activeNotePath, activeNodeFocused, movedActiveNode, parentsOfAddedNodes); @@ -1280,7 +1254,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { } else { refreshCtx.noteIdsToUpdate.add(attrRow.noteId); } - } else if (attrRow.type === "label" && attrRow.name === "archived" && attrRow.noteId) { + } else if (attrRow.type === "label" && (attrRow.name === "archived" || attrRow.name === "subtreeHidden") && attrRow.noteId) { const note = froca.getNoteFromCache(attrRow.noteId); if (note) { @@ -1365,18 +1339,34 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { } else if (frocaBranch) { // make sure it's loaded // we're forcing lazy since it's not clear if the whole required subtree is in froca - const newNode = this.prepareNode(frocaBranch, true); - if (newNode) { - parentNode.addChildren([newNode]); - } + if (!parentNode.data.subtreeHidden) { + const newNode = this.prepareNode(frocaBranch, true); + if (newNode) { + parentNode.addChildren([newNode]); + } - if (frocaBranch?.isExpanded && note && note.hasChildren()) { - refreshCtx.noteIdsToReload.add(frocaBranch.noteId); - } + if (frocaBranch?.isExpanded && note && note.hasChildren()) { + refreshCtx.noteIdsToReload.add(frocaBranch.noteId); + } - this.sortChildren(parentNode); + this.sortChildren(parentNode); + } else if (branchRow.componentId === this.componentId) { + // Display the toast and focus to parent note only if we know for sure that the operation comes from the tree. + const parentNote = froca.getNoteFromCache(parentNode.data.noteId || ""); + toastService.showPersistent({ + id: `subtree-hidden-moved`, + title: t("note_tree.subtree-hidden-moved-title", { title: parentNote?.title }), + message: parentNote?.type === "book" + ? t("note_tree.subtree-hidden-moved-description-collection") + : t("note_tree.subtree-hidden-moved-description-other"), + icon: "bx bx-hide", + timeout: 5_000, + }); + parentNode.setActive(true); + } // this might be a first child which would force an icon change + // also update the count if the subtree is hidden. if (branchRow.parentNoteId) { refreshCtx.noteIdsToUpdate.add(branchRow.parentNoteId); } @@ -1392,7 +1382,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { } async #executeTreeUpdates(refreshCtx: RefreshContext, loadResults: LoadResults) { - await this.batchUpdate(async () => { + const performUpdates = async () => { for (const noteId of refreshCtx.noteIdsToReload) { for (const node of this.getNodesByNoteId(noteId)) { await node.load(true); @@ -1408,7 +1398,19 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { } } } - }); + }; + + if (refreshCtx.noteIdsToReload.size + refreshCtx.noteIdsToUpdate.size >= BATCH_UPDATE_THRESHOLD) { + /** + * Batch updates are used for large number of updates to prevent multiple re-renders, however in the context of small updates (such as changing a note title) + * it can cause up to 400ms of delay for ~8k notes which is not acceptable. Therefore we use batching only for larger number of updates. + * Without batching, the updates would take a couple of milliseconds. + * We still keep the batching for potential cases where there are many updates, for example in a sync. + */ + await this.batchUpdate(performUpdates); + } else { + await performUpdates(); + } // for some reason, node update cannot be in the batchUpdate() block (node is not re-rendered) for (const noteId of refreshCtx.noteIdsToUpdate) { @@ -1672,7 +1674,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { const toNode = node.getPrevSibling(); if (toNode !== null) { - branchService.moveToParentNote([node.data.branchId], toNode.data.branchId); + branchService.moveToParentNote([node.data.branchId], toNode.data.branchId, this.componentId); } } @@ -1809,12 +1811,12 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { #moveLaunchers(selectedOrActiveBranchIds: string[], desktopParent: string, mobileParent: string) { const desktopLaunchersToMove = selectedOrActiveBranchIds.filter((branchId) => !branchId.startsWith("_lbMobile")); if (desktopLaunchersToMove) { - branchService.moveToParentNote(desktopLaunchersToMove, `_lbRoot_${ desktopParent}`); + branchService.moveToParentNote(desktopLaunchersToMove, `_lbRoot_${ desktopParent}`, this.componentId); } const mobileLaunchersToMove = selectedOrActiveBranchIds.filter((branchId) => branchId.startsWith("_lbMobile")); if (mobileLaunchersToMove) { - branchService.moveToParentNote(mobileLaunchersToMove, `_lbMobileRoot_${ mobileParent}`); + branchService.moveToParentNote(mobileLaunchersToMove, `_lbMobileRoot_${mobileParent}`, this.componentId); } } @@ -1882,3 +1884,112 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { return items; } } + +function buildEnhanceTitle() { + const createChildTemplate = document.createElement("span"); + createChildTemplate.className = "tree-item-button tn-icon add-note-button bx bx-plus"; + createChildTemplate.title = t("note_tree.create-child-note"); + + return async function enhanceTitle(event: Event, + data: { + node: Fancytree.FancytreeNode; + noteId: string; + }) { + const node = data.node; + + if (!node.data.noteId) { + // if there's "non-note" node, then don't enhance + // this can happen for e.g. "Load error!" node + return; + } + + const note = froca.getNoteFromCache(node.data.noteId); + if (!note) return; + + const activeNoteContext = appContext.tabManager.getActiveContext(); + + const $span = $(node.span); + + $span.find(".tree-item-button").remove(); + $span.find(".note-indicator-icon").remove(); + + const isHoistedNote = activeNoteContext && activeNoteContext.hoistedNoteId === note.noteId && note.noteId !== "root"; + + if (note.hasLabel("workspace") && !isHoistedNote) { + const $enterWorkspaceButton = $(``).on( + "click", + cancelClickPropagation + ); + + $span.append($enterWorkspaceButton); + } + + if (note.type === "search") { + const $refreshSearchButton = $(``).on( + "click", + cancelClickPropagation + ); + + $span.append($refreshSearchButton); + } + + // TODO: Deduplicate with server's notes.ts#getAndValidateParent + const isSubtreeHidden = note.isLabelTruthy("subtreeHidden"); + if (!["search", "launcher"].includes(note.type) + && !note.isOptions() + && !note.isLaunchBarConfig() + && !note.noteId.startsWith("_help") + && !isSubtreeHidden + && !node.extraClasses.includes("spotlighted-node") + ) { + const createChildItem = createChildTemplate.cloneNode(); + createChildItem.addEventListener("click", cancelClickPropagation); + node.span.append(createChildItem); + } + + if (isHoistedNote) { + const $unhoistButton = $(``).on("click", cancelClickPropagation); + + $span.append($unhoistButton); + } + + // Add clone indicator with tooltip if note has multiple parents + const parentNotes = note.getParentNotes(); + const realParents: FNote[] = []; + for (const parent of parentNotes) { + if (parent.noteId !== "_share" && parent.noteId !== "_lbBookmarks" && parent.type !== "search") { + realParents.push(parent); + } + } + + if (realParents.length > 1) { + const parentTitles = realParents.map((p) => p.title).join(", "); + const tooltipText = realParents.length === 2 + ? t("note_tree.clone-indicator-tooltip-single", { parent: realParents[1].title }) + : t("note_tree.clone-indicator-tooltip", { count: realParents.length, parents: parentTitles }); + + const $cloneIndicator = $(``); + $cloneIndicator.attr("title", tooltipText); + $span.find(".fancytree-title").append($cloneIndicator); + } + + // Add shared indicator with tooltip if note is shared + if (note.isShared()) { + const shareId = note.getOwnedLabelValue("shareAlias") || note.noteId; + const shareUrl = `${location.origin}${location.pathname}share/${shareId}`; + const tooltipText = t("note_tree.shared-indicator-tooltip-with-url", { url: shareUrl }); + + const $sharedIndicator = $(``); + $sharedIndicator.attr("title", tooltipText); + $span.find(".fancytree-title").append($sharedIndicator); + } + + // Add a badge with the number of items if it hides children. + const count = note.getChildNoteIds().length; + if (isSubtreeHidden && count > 0) { + const $badge = $(`${count}`); + $badge.attr("title", t("note_tree.subtree-hidden-tooltip", { count })); + $span.find(".fancytree-title").append($badge); + } + }; +} diff --git a/apps/client/src/widgets/react/hooks.tsx b/apps/client/src/widgets/react/hooks.tsx index d0031fe07..8eb2cc0ef 100644 --- a/apps/client/src/widgets/react/hooks.tsx +++ b/apps/client/src/widgets/react/hooks.tsx @@ -646,17 +646,13 @@ export function useNoteLabelBoolean(note: FNote | undefined | null, labelName: F const setter = useCallback((value: boolean) => { if (note) { - if (value) { - attributes.setLabel(note.noteId, labelName, ""); - } else { - attributes.removeOwnedLabelByName(note, labelName); - } + attributes.setBooleanWithInheritance(note, labelName, value); } - }, [note]); + }, [note, labelName]); useDebugValue(labelName); - const labelValue = !!note?.hasLabel(labelName); + const labelValue = !!note?.isLabelTruthy(labelName); return [ labelValue, setter ] as const; } diff --git a/apps/client/src/widgets/sidebar/TableOfContents.tsx b/apps/client/src/widgets/sidebar/TableOfContents.tsx index c072c8599..483ddb179 100644 --- a/apps/client/src/widgets/sidebar/TableOfContents.tsx +++ b/apps/client/src/widgets/sidebar/TableOfContents.tsx @@ -2,12 +2,14 @@ import "./TableOfContents.css"; import { CKTextEditor, ModelElement } from "@triliumnext/ckeditor5"; import clsx from "clsx"; -import { useCallback, useEffect, useState } from "preact/hooks"; +import { useCallback, useEffect, useRef, useState } from "preact/hooks"; import { t } from "../../services/i18n"; +import math from "../../services/math"; import { randomString } from "../../services/utils"; import { useActiveNoteContext, useContentElement, useGetContextData, useIsNoteReadOnly, useNoteProperty, useTextEditor } from "../react/hooks"; import Icon from "../react/Icon"; +import RawHtml from "../react/RawHtml"; import RightPanelWidget from "./RightPanelWidget"; //#region Generic impl. @@ -80,6 +82,22 @@ function TableOfContentsHeading({ heading, scrollToHeading, activeHeadingId }: { }) { const [ collapsed, setCollapsed ] = useState(false); const isActive = heading.id === activeHeadingId; + const contentRef = useRef(null); + + // Render math equations after component mounts/updates + useEffect(() => { + if (!contentRef.current) return; + const mathElements = contentRef.current.querySelectorAll(".ck-math-tex"); + + for (const mathEl of mathElements ?? []) { + try { + math.render(mathEl.textContent || "", mathEl as HTMLElement); + } catch (e) { + console.warn("Failed to render math in TOC:", e); + } + } + }, [heading.text]); + return ( <>
  • @@ -90,12 +108,14 @@ function TableOfContentsHeading({ heading, scrollToHeading, activeHeadingId }: { onClick={() => setCollapsed(!collapsed)} /> )} - scrollToHeading(heading)} - >{heading.text} + html={heading.text} + />
  • - {heading.children && ( + {heading.children.length > 0 && (
      {heading.children.map(heading => )}
    @@ -189,9 +209,23 @@ function extractTocFromTextEditor(editor: CKTextEditor) { if (type !== "elementStart" || !item.is('element') || !item.name.startsWith('heading')) continue; const level = Number(item.name.replace( 'heading', '' )); - const text = Array.from( item.getChildren() ) - .map( c => c.is( '$text' ) ? c.data : '' ) - .join( '' ); + + // Convert model element to view, then to DOM to get HTML + const viewEl = editor.editing.mapper.toViewElement(item); + let text = ''; + if (viewEl) { + const domEl = editor.editing.view.domConverter.mapViewToDom(viewEl); + if (domEl instanceof HTMLElement) { + text = domEl.innerHTML; + } + } + + // Fallback to plain text if conversion fails + if (!text) { + text = Array.from( item.getChildren() ) + .map( c => c.is( '$text' ) ? c.data : '' ) + .join( '' ); + } // Assign a unique ID let tocId = item.getAttribute(TOC_ID) as string | undefined; diff --git a/apps/client/src/widgets/type_widgets/helpers/SplitEditor.css b/apps/client/src/widgets/type_widgets/helpers/SplitEditor.css index 72f680b01..0dce268ea 100644 --- a/apps/client/src/widgets/type_widgets/helpers/SplitEditor.css +++ b/apps/client/src/widgets/type_widgets/helpers/SplitEditor.css @@ -15,6 +15,8 @@ .note-detail-split .note-detail-split-editor { width: 100%; flex-grow: 1; + min-width: 0; + min-height: 0; } .note-detail-split .note-detail-split-editor .note-detail-code { @@ -30,6 +32,7 @@ margin: 5px; white-space: pre-wrap; font-size: 0.85em; + overflow: auto; } .note-detail-split .note-detail-split-preview { diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 467c87910..00cc6e041 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@triliumnext/desktop", - "version": "0.101.1", + "version": "0.101.3", "description": "Build your personal knowledge base with Trilium Notes", "private": true, "main": "src/main.ts", diff --git a/apps/server-e2e/src/layout/tab_bar.spec.ts b/apps/server-e2e/src/layout/tab_bar.spec.ts index 90e17afef..791064966 100644 --- a/apps/server-e2e/src/layout/tab_bar.spec.ts +++ b/apps/server-e2e/src/layout/tab_bar.spec.ts @@ -1,4 +1,5 @@ -import { test, expect } from "@playwright/test"; +import { expect,test } from "@playwright/test"; + import App from "../support/app"; const NOTE_TITLE = "Trilium Integration Test DB"; @@ -65,21 +66,21 @@ test("Tabs are restored in right order", async ({ page, context }) => { // Open three tabs. await app.closeAllTabs(); await app.goToNoteInNewTab("Code notes"); + await expect(app.getActiveTab()).toContainText("Code notes"); await app.addNewTab(); await app.goToNoteInNewTab("Text notes"); + await expect(app.getActiveTab()).toContainText("Text notes"); await app.addNewTab(); await app.goToNoteInNewTab("Mermaid"); + await expect(app.getActiveTab()).toContainText("Mermaid"); // Select the mid one. await app.getTab(1).click(); await expect(app.noteTreeActiveNote).toContainText("Text notes"); - await expect(app.getTab(0)).toContainText("Code notes"); - await expect(app.getTab(1)).toContainText("Text notes"); - await expect(app.getTab(2)).toContainText("Mermaid"); // Refresh the page and check the order. await app.goto( { preserveTabs: true }); - await expect(app.getTab(0)).toContainText("Code notes", { timeout: 15_000 }); + await expect(app.getTab(0)).toContainText("Code notes"); await expect(app.getTab(1)).toContainText("Text notes"); await expect(app.getTab(2)).toContainText("Mermaid"); @@ -128,8 +129,8 @@ test("New tab displays workspaces", async ({ page, context }) => { const workspaceNotesEl = app.currentNoteSplitContent.locator(".workspace-notes"); await expect(workspaceNotesEl).toBeVisible(); - expect(workspaceNotesEl).toContainText("Personal"); - expect(workspaceNotesEl).toContainText("Work"); + await expect(workspaceNotesEl).toContainText("Personal"); + await expect(workspaceNotesEl).toContainText("Work"); await expect(workspaceNotesEl.locator(".bx.bxs-user")).toBeVisible(); await expect(workspaceNotesEl.locator(".bx.bx-briefcase-alt")).toBeVisible(); diff --git a/apps/server-e2e/src/note_types/pdf.spec.ts b/apps/server-e2e/src/note_types/pdf.spec.ts index 4d5543fda..d79ddb37e 100644 --- a/apps/server-e2e/src/note_types/pdf.spec.ts +++ b/apps/server-e2e/src/note_types/pdf.spec.ts @@ -1,12 +1,12 @@ -import test, { BrowserContext, expect, Page } from "@playwright/test"; +import test, { expect, Page } from "@playwright/test"; import App from "../support/app"; test.beforeEach(async ({ page, context }) => { - const app = await setLayout({ page, context }, true); + const app = new App(page, context); + await app.goto(); await app.setOption("rightPaneCollapsedItems", "[]"); }); -test.afterEach(async ({ page, context }) => await setLayout({ page, context }, false)); test("Table of contents works", async ({ page, context }) => { const app = new App(page, context); @@ -73,13 +73,15 @@ test("Attachments listing works", async ({ page, context }) => { test("Download original PDF works", async ({ page, context }) => { const app = new App(page, context); await app.goto(); - await app.goToNoteInNewTab("Dacia Logan.pdf"); + await app.goToNoteInNewTab("Layers test.pdf"); const pdfHelper = new PdfHelper(app); await pdfHelper.toBeInitialized(); + const downloadButton = app.currentNoteSplit.locator(".icon-action.bx.bx-download"); + await expect(downloadButton).toBeVisible(); const [ download ] = await Promise.all([ page.waitForEvent("download"), - app.currentNoteSplit.locator(".icon-action.bx.bx-download").click() + downloadButton.click() ]); expect(download).toBeDefined(); }); @@ -105,13 +107,6 @@ test("Layers listing works", async ({ page, context }) => { await expect(layersList.locator(".pdf-layer-item")).toHaveCount(0); }); -async function setLayout({ page, context}: { page: Page; context: BrowserContext }, newLayout: boolean) { - const app = new App(page, context); - await app.goto(); - await app.setOption("newLayout", newLayout ? "true" : "false"); - return app; -} - class PdfHelper { private contentFrame: ReturnType; @@ -125,5 +120,6 @@ class PdfHelper { async toBeInitialized() { await expect(this.contentFrame.locator("#pageNumber")).toBeVisible(); + await expect(this.contentFrame.locator(".page")).toBeVisible(); } } diff --git a/apps/server-e2e/src/note_types/text.spec.ts b/apps/server-e2e/src/note_types/text.spec.ts index c99ad5d7d..052745ee2 100644 --- a/apps/server-e2e/src/note_types/text.spec.ts +++ b/apps/server-e2e/src/note_types/text.spec.ts @@ -1,4 +1,5 @@ -import { test, expect, Page } from "@playwright/test"; +import { expect, test } from "@playwright/test"; + import App from "../support/app"; test("Table of contents is displayed", async ({ page, context }) => { @@ -8,7 +9,7 @@ test("Table of contents is displayed", async ({ page, context }) => { await app.goToNoteInNewTab("Table of contents"); await expect(app.sidebar).toContainText("Table of Contents"); - const rootList = app.sidebar.locator(".toc-widget > span > ol"); + const rootList = app.sidebar.locator(".toc > ol"); // Heading 1.1 // Heading 1.1 @@ -42,7 +43,7 @@ test("Highlights list is displayed", async ({ page, context }) => { await app.closeAllTabs(); await app.goToNoteInNewTab("Highlights list"); - await expect(app.sidebar).toContainText("Highlights List"); + await expect(app.sidebar).toContainText("10 highlights"); const rootList = app.sidebar.locator(".highlights-list ol"); let index = 0; for (const highlightedEl of ["Bold 1", "Italic 1", "Underline 1", "Colored text 1", "Background text 1", "Bold 2", "Italic 2", "Underline 2", "Colored text 2", "Background text 2"]) { @@ -64,6 +65,8 @@ test("Displays math popup", async ({ page, context }) => { await expect(mathForm).toBeVisible(); const input = mathForm.locator(".ck-input").first(); + await expect(input).toBeVisible(); + await expect(input).toBeEnabled(); await input.click(); await input.fill("e=mc^2"); await page.waitForTimeout(100); diff --git a/apps/server-e2e/src/support/app.ts b/apps/server-e2e/src/support/app.ts index 12097c656..86cbb855a 100644 --- a/apps/server-e2e/src/support/app.ts +++ b/apps/server-e2e/src/support/app.ts @@ -37,7 +37,7 @@ export default class App { this.noteTreeHoistedNote = this.noteTree.locator(".fancytree-node", { has: page.locator(".unhoist-button") }); this.launcherBar = page.locator("#launcher-container"); this.currentNoteSplit = page.locator(".note-split:not(.hidden-ext)"); - this.currentNoteSplitTitle = this.currentNoteSplit.locator(".note-title"); + this.currentNoteSplitTitle = this.currentNoteSplit.locator(".note-title").first(); this.currentNoteSplitContent = this.currentNoteSplit.locator(".note-detail-printable.visible"); this.sidebar = page.locator("#right-pane"); } @@ -68,13 +68,15 @@ export default class App { async goToNoteInNewTab(noteTitle: string) { const autocomplete = this.currentNoteSplit.locator(".note-autocomplete"); + await expect(autocomplete).toBeVisible(); await autocomplete.fill(noteTitle); const resultsSelector = this.currentNoteSplit.locator(".note-detail-empty-results"); await expect(resultsSelector).toContainText(noteTitle); - await resultsSelector.locator(".aa-suggestion", { hasText: noteTitle }) - .nth(1) // Select the second one, as the first one is "Create a new note" - .click(); + const suggestionSelector = resultsSelector.locator(".aa-suggestion") + .nth(1); // Select the second one (best candidate), as the first one is "Create a new note" + await expect(suggestionSelector).toContainText(noteTitle); + suggestionSelector.click(); } async goToSettings() { diff --git a/apps/server/package.json b/apps/server/package.json index ecde42986..bf4b4750c 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -1,6 +1,6 @@ { "name": "@triliumnext/server", - "version": "0.101.1", + "version": "0.101.3", "description": "The server-side component of TriliumNext, which exposes the client via the web, allows for sync and provides a REST API for both internal and external use.", "private": true, "main": "./src/main.ts", diff --git a/apps/server/spec/db/document.db b/apps/server/spec/db/document.db index c488fb107..ad993226e 100644 Binary files a/apps/server/spec/db/document.db and b/apps/server/spec/db/document.db differ diff --git a/apps/server/src/assets/doc_notes/en/User Guide/!!!meta.json b/apps/server/src/assets/doc_notes/en/User Guide/!!!meta.json index 56643ced6..8abbb2f5c 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/!!!meta.json +++ b/apps/server/src/assets/doc_notes/en/User Guide/!!!meta.json @@ -1 +1 @@ -[{"id":"_help_BOCnjTMBCoxW","title":"Feature Highlights","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Feature Highlights"},{"name":"iconClass","value":"bx bx-star","type":"label"}]},{"id":"_help_Otzi9La2YAUX","title":"Installation & Setup","type":"book","attributes":[{"name":"iconClass","value":"bx bx-cog","type":"label"}],"children":[{"id":"_help_poXkQfguuA0U","title":"Desktop Installation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation"},{"name":"iconClass","value":"bx bx-desktop","type":"label"}],"children":[{"id":"_help_nRqcgfTb97uV","title":"Using the desktop application as a server","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/Using the desktop application "},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_Rp0q8bSP6Ayl","title":"System Requirements","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/System Requirements"},{"name":"iconClass","value":"bx bx-chip","type":"label"}]},{"id":"_help_Un4wj2Mak2Ky","title":"Nix flake","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/Nix flake"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]}]},{"id":"_help_WOcw2SLH6tbX","title":"Server Installation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation"},{"name":"iconClass","value":"bx bx-server","type":"label"}],"children":[{"id":"_help_Dgg7bR3b6K9j","title":"1. Installing the server","type":"book","attributes":[{"name":"iconClass","value":"bx bx-folder","type":"label"}],"children":[{"id":"_help_3tW6mORuTHnB","title":"Packaged version for Linux","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged version for Linux"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]},{"id":"_help_rWX5eY045zbE","title":"Using Docker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Using Docker"},{"name":"iconClass","value":"bx bxl-docker","type":"label"}]},{"id":"_help_moVgBcoxE3EK","title":"On NixOS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/On NixOS"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]},{"id":"_help_J1Bb6lVlwU5T","title":"Manually","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manually"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}]},{"id":"_help_DCmT6e7clMoP","title":"Using Kubernetes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Using Kubernetes"},{"name":"iconClass","value":"bx bxl-kubernetes","type":"label"}]},{"id":"_help_klCWNks3ReaQ","title":"Multiple server instances","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Multiple server instances"},{"name":"iconClass","value":"bx bxs-user-account","type":"label"}]}]},{"id":"_help_vcjrb3VVYPZI","title":"2. Reverse proxy","type":"book","attributes":[{"name":"iconClass","value":"bx bx-folder","type":"label"}],"children":[{"id":"_help_ud6MShXL4WpO","title":"Nginx","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Nginx"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_fDLvzOx29Pfg","title":"Apache using Docker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Apache using Docker"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_LLzSMXACKhUs","title":"Trusted proxy","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Trusted proxy"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_5ERVJb9s4FRD","title":"Traefik","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Traefik"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_l2VkvOwUNfZj","title":"HTTPS (TLS)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/HTTPS (TLS)"},{"name":"iconClass","value":"bx bx-lock-alt","type":"label"}]},{"id":"_help_0hzsNCP31IAB","title":"Authentication","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Authentication"},{"name":"iconClass","value":"bx bx-user","type":"label"}]},{"id":"_help_7DAiwaf8Z7Rz","title":"Multi-Factor Authentication","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Multi-Factor Authentication"},{"name":"iconClass","value":"bx bx-stopwatch","type":"label"}]},{"id":"_help_Un4wj2Mak2Ky","title":"Nix flake","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Nix flake.clone"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_yeEaYqosGLSh","title":"Third-party cloud hosting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Third-party cloud hosting"},{"name":"iconClass","value":"bx bx-cloud","type":"label"}]},{"id":"_help_iGTnKjubbXkA","title":"System Requirements","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/System Requirements"},{"name":"iconClass","value":"bx bx-chip","type":"label"}]}]},{"id":"_help_cbkrhQjrkKrh","title":"Synchronization","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Synchronization"},{"name":"iconClass","value":"bx bx-sync","type":"label"}]},{"id":"_help_RDslemsQ6gCp","title":"Mobile Frontend","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Mobile Frontend"},{"name":"iconClass","value":"bx bx-mobile-alt","type":"label"}]},{"id":"_help_MtPxeAWVAzMg","title":"Web Clipper","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Web Clipper"},{"name":"iconClass","value":"bx bx-paperclip","type":"label"}]},{"id":"_help_n1lujUxCwipy","title":"Upgrading TriliumNext","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Upgrading TriliumNext"},{"name":"iconClass","value":"bx bx-up-arrow-alt","type":"label"}]},{"id":"_help_ODY7qQn5m2FT","title":"Backup","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Backup"},{"name":"iconClass","value":"bx bx-hdd","type":"label"}]},{"id":"_help_tAassRL4RSQL","title":"Data directory","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Data directory"},{"name":"iconClass","value":"bx bx-folder-open","type":"label"}]}]},{"id":"_help_gh7bpGYxajRS","title":"Basic Concepts and Features","type":"book","attributes":[{"name":"iconClass","value":"bx bx-help-circle","type":"label"}],"children":[{"id":"_help_Vc8PjrjAGuOp","title":"UI Elements","type":"book","attributes":[{"name":"iconClass","value":"bx bx-window-alt","type":"label"}],"children":[{"id":"_help_x0JgW8UqGXvq","title":"Vertical and horizontal layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Vertical and horizontal layout"},{"name":"iconClass","value":"bx bxs-layout","type":"label"}]},{"id":"_help_x3i7MxGccDuM","title":"Global menu","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Global menu"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_oPVyFC7WL2Lp","title":"Note Tree","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree"},{"name":"iconClass","value":"bx bxs-tree-alt","type":"label"}],"children":[{"id":"_help_YtSN43OrfzaA","title":"Note tree contextual menu","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Note tree contextual menu"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_yTjUdsOi4CIE","title":"Multiple selection","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Multiple selection"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_DvdZhoQZY9Yd","title":"Keyboard shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Keyboard shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]}]},{"id":"_help_BlN9DFI679QC","title":"Ribbon","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon"},{"name":"iconClass","value":"bx bx-dots-horizontal","type":"label"}]},{"id":"_help_3seOhtN8uLIY","title":"Tabs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Tabs"},{"name":"iconClass","value":"bx bx-dock-top","type":"label"}]},{"id":"_help_xYmIYSP6wE3F","title":"Launch Bar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Launch Bar"},{"name":"iconClass","value":"bx bx-sidebar","type":"label"}]},{"id":"_help_8YBEPzcpUgxw","title":"Note buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note buttons"},{"name":"iconClass","value":"bx bx-dots-vertical-rounded","type":"label"}]},{"id":"_help_4TIF1oA4VQRO","title":"Options","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Options"},{"name":"iconClass","value":"bx bx-cog","type":"label"}]},{"id":"_help_luNhaphA37EO","title":"Split View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Split View"},{"name":"iconClass","value":"bx bx-dock-right","type":"label"}]},{"id":"_help_XpOYSgsLkTJy","title":"Floating buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Floating buttons"},{"name":"iconClass","value":"bx bx-rectangle","type":"label"}]},{"id":"_help_RnaPdbciOfeq","title":"Right Sidebar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Right Sidebar"},{"name":"iconClass","value":"bx bxs-dock-right","type":"label"}]},{"id":"_help_r5JGHN99bVKn","title":"Recent Changes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Recent Changes"},{"name":"iconClass","value":"bx bx-history","type":"label"}]},{"id":"_help_ny318J39E5Z0","title":"Zoom","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Zoom"},{"name":"iconClass","value":"bx bx-zoom-in","type":"label"}]},{"id":"_help_lgKX7r3aL30x","title":"Note Tooltip","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tooltip"},{"name":"iconClass","value":"bx bx-message-detail","type":"label"}]},{"id":"_help_IjZS7iK5EXtb","title":"New Layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout"},{"name":"iconClass","value":"bx bx-layout","type":"label"}],"children":[{"id":"_help_I6p2a06hdnL6","title":"Breadcrumb","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout/Breadcrumb"},{"name":"iconClass","value":"bx bx-chevron-right","type":"label"}]},{"id":"_help_AlJ73vBCjWDw","title":"Status bar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout/Status bar"},{"name":"iconClass","value":"bx bx-dock-bottom","type":"label"}]}]}]},{"id":"_help_BFs8mudNFgCS","title":"Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes"},{"name":"iconClass","value":"bx bx-notepad","type":"label"}],"children":[{"id":"_help_p9kXRFAkwN4o","title":"Note Icons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note Icons"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_0vhv7lsOLy82","title":"Attachments","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Attachments"},{"name":"iconClass","value":"bx bx-paperclip","type":"label"}]},{"id":"_help_IakOLONlIfGI","title":"Cloning Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Cloning Notes"},{"name":"iconClass","value":"bx bx-duplicate","type":"label"}],"children":[{"id":"_help_TBwsyfadTA18","title":"Branch prefix","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Cloning Notes/Branch prefix"},{"name":"iconClass","value":"bx bx-rename","type":"label"}]}]},{"id":"_help_bwg0e8ewQMak","title":"Protected Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Protected Notes"},{"name":"iconClass","value":"bx bx-lock-alt","type":"label"}]},{"id":"_help_MKmLg5x6xkor","title":"Archived Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Archived Notes"},{"name":"iconClass","value":"bx bx-box","type":"label"}]},{"id":"_help_vZWERwf8U3nx","title":"Note Revisions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note Revisions"},{"name":"iconClass","value":"bx bx-history","type":"label"}]},{"id":"_help_aGlEvb9hyDhS","title":"Sorting Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Sorting Notes"},{"name":"iconClass","value":"bx bx-sort-up","type":"label"}]},{"id":"_help_NRnIZmSMc5sj","title":"Printing & Exporting as PDF","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF"},{"name":"iconClass","value":"bx bx-printer","type":"label"}]},{"id":"_help_CoFPLs3dRlXc","title":"Read-Only Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Read-Only Notes"},{"name":"iconClass","value":"bx bx-edit-alt","type":"label"}]},{"id":"_help_0ESUbbAxVnoK","title":"Note List","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note List"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]}]},{"id":"_help_wArbEsdSae6g","title":"Navigation","type":"book","attributes":[{"name":"iconClass","value":"bx bx-navigation","type":"label"}],"children":[{"id":"_help_kBrnXNG3Hplm","title":"Tree Concepts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Tree Concepts"},{"name":"iconClass","value":"bx bx-pyramid","type":"label"}]},{"id":"_help_MMiBEQljMQh2","title":"Note Navigation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Note Navigation"},{"name":"iconClass","value":"bx bxs-navigation","type":"label"}]},{"id":"_help_Ms1nauBra7gq","title":"Quick search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Quick search"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]},{"id":"_help_F1r9QtzQLZqm","title":"Jump to...","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Jump to"},{"name":"iconClass","value":"bx bx-send","type":"label"}]},{"id":"_help_eIg8jdvaoNNd","title":"Search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Search"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]},{"id":"_help_u3YFHC9tQlpm","title":"Bookmarks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Bookmarks"},{"name":"iconClass","value":"bx bx-bookmarks","type":"label"}]},{"id":"_help_OR8WJ7Iz9K4U","title":"Note Hoisting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Note Hoisting"},{"name":"iconClass","value":"bx bxs-chevrons-up","type":"label"}]},{"id":"_help_ZjLYv08Rp3qC","title":"Quick edit","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Quick edit"},{"name":"iconClass","value":"bx bx-edit","type":"label"}]},{"id":"_help_9sRHySam5fXb","title":"Workspaces","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Workspaces"},{"name":"iconClass","value":"bx bx-door-open","type":"label"}]},{"id":"_help_xWtq5NUHOwql","title":"Similar Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Similar Notes"},{"name":"iconClass","value":"bx bx-bar-chart","type":"label"}]},{"id":"_help_McngOG2jbUWX","title":"Search in note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Search in note"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]}]},{"id":"_help_A9Oc6YKKc65v","title":"Keyboard Shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Keyboard Shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]},{"id":"_help_Wy267RK4M69c","title":"Themes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes"},{"name":"iconClass","value":"bx bx-palette","type":"label"}],"children":[{"id":"_help_VbjZvtUek0Ln","title":"Theme Gallery","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes/Theme Gallery"},{"name":"iconClass","value":"bx bx-book-reader","type":"label"}]},{"id":"_help_gOKqSJgXLcIj","title":"Icon Packs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_mHbBMPDPkVV5","title":"Import & Export","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export"},{"name":"iconClass","value":"bx bx-import","type":"label"}],"children":[{"id":"_help_Oau6X9rCuegd","title":"Markdown","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Markdown"},{"name":"iconClass","value":"bx bxl-markdown","type":"label"}],"children":[{"id":"_help_rJ9grSgoExl9","title":"Supported syntax","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Markdown/Supported syntax"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}]}]},{"id":"_help_syuSEKf2rUGr","title":"Evernote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Evernote"},{"name":"iconClass","value":"bx bx-window-open","type":"label"}]},{"id":"_help_GnhlmrATVqcH","title":"OneNote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/OneNote"},{"name":"iconClass","value":"bx bx-window-open","type":"label"}]}]},{"id":"_help_rC3pL2aptaRE","title":"Zen mode","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Zen mode"},{"name":"iconClass","value":"bx bxs-yin-yang","type":"label"}]}]},{"id":"_help_s3YCWHBfmYuM","title":"Quick Start","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Quick Start"},{"name":"iconClass","value":"bx bx-run","type":"label"}]},{"id":"_help_i6dbnitykE5D","title":"FAQ","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/FAQ"},{"name":"iconClass","value":"bx bx-question-mark","type":"label"}]},{"id":"_help_KSZ04uQ2D1St","title":"Note Types","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types"},{"name":"iconClass","value":"bx bx-edit","type":"label"}],"children":[{"id":"_help_iPIMuisry3hd","title":"Text","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text"},{"name":"iconClass","value":"bx bx-note","type":"label"}],"children":[{"id":"_help_NwBbFdNZ9h7O","title":"Block quotes & admonitions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Block quotes & admonitions"},{"name":"iconClass","value":"bx bx-info-circle","type":"label"}]},{"id":"_help_oSuaNgyyKnhu","title":"Bookmarks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Bookmarks"},{"name":"iconClass","value":"bx bx-bookmark","type":"label"}]},{"id":"_help_veGu4faJErEM","title":"Content language & Right-to-left support","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Content language & Right-to-le"},{"name":"iconClass","value":"bx bx-align-right","type":"label"}]},{"id":"_help_2x0ZAX9ePtzV","title":"Cut to subnote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Cut to subnote"},{"name":"iconClass","value":"bx bx-cut","type":"label"}]},{"id":"_help_UYuUB1ZekNQU","title":"Developer-specific formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Developer-specific formatting"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}],"children":[{"id":"_help_QxEyIjRBizuC","title":"Code blocks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Developer-specific formatting/Code blocks"},{"name":"iconClass","value":"bx bx-code","type":"label"}]}]},{"id":"_help_AgjCISero73a","title":"Footnotes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Footnotes"},{"name":"iconClass","value":"bx bx-bracket","type":"label"}]},{"id":"_help_nRhnJkTT8cPs","title":"Formatting toolbar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Formatting toolbar"},{"name":"iconClass","value":"bx bx-text","type":"label"}]},{"id":"_help_Gr6xFaF6ioJ5","title":"General formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/General formatting"},{"name":"iconClass","value":"bx bx-bold","type":"label"}]},{"id":"_help_AxshuNRegLAv","title":"Highlights list","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Highlights list"},{"name":"iconClass","value":"bx bx-highlight","type":"label"}]},{"id":"_help_mT0HEkOsz6i1","title":"Images","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Images"},{"name":"iconClass","value":"bx bx-image-alt","type":"label"}],"children":[{"id":"_help_0Ofbk1aSuVRu","title":"Image references","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Images/Image references"},{"name":"iconClass","value":"bx bxs-file-image","type":"label"}]}]},{"id":"_help_nBAXQFj20hS1","title":"Include Note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Include Note"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_CohkqWQC1iBv","title":"Insert buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Insert buttons"},{"name":"iconClass","value":"bx bx-plus","type":"label"}]},{"id":"_help_oiVPnW8QfnvS","title":"Keyboard shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Keyboard shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]},{"id":"_help_QEAPj01N5f7w","title":"Links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links"},{"name":"iconClass","value":"bx bx-link-alt","type":"label"}],"children":[{"id":"_help_3IDVtesTQ8ds","title":"External links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links/External links"},{"name":"iconClass","value":"bx bx-link-external","type":"label"}]},{"id":"_help_hrZ1D00cLbal","title":"Internal (reference) links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links/Internal (reference) links"},{"name":"iconClass","value":"bx bx-link","type":"label"}]}]},{"id":"_help_S6Xx8QIWTV66","title":"Lists","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Lists"},{"name":"iconClass","value":"bx bx-list-ul","type":"label"}]},{"id":"_help_QrtTYPmdd1qq","title":"Markdown-like formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Markdown-like formatting"},{"name":"iconClass","value":"bx bxl-markdown","type":"label"}]},{"id":"_help_YfYAtQBcfo5V","title":"Math Equations","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Math Equations"},{"name":"iconClass","value":"bx bx-math","type":"label"}]},{"id":"_help_dEHYtoWWi8ct","title":"Other features","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Other features"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_gLt3vA97tMcp","title":"Premium features","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features"},{"name":"iconClass","value":"bx bx-star","type":"label"}],"children":[{"id":"_help_ZlN4nump6EbW","title":"Slash Commands","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Slash Commands"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_pwc194wlRzcH","title":"Text Snippets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Text Snippets"},{"name":"iconClass","value":"bx bx-align-left","type":"label"}]},{"id":"_help_5wZallV2Qo1t","title":"Format Painter","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Format Painter"},{"name":"iconClass","value":"bx bxs-paint-roll","type":"label"}]}]},{"id":"_help_BFvAtE74rbP6","title":"Table of contents","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Table of contents"},{"name":"iconClass","value":"bx bx-heading","type":"label"}]},{"id":"_help_NdowYOC1GFKS","title":"Tables","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Tables"},{"name":"iconClass","value":"bx bx-table","type":"label"}]}]},{"id":"_help_6f9hih2hXXZk","title":"Code","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Code"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_m523cpzocqaD","title":"Saved Search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Saved Search"},{"name":"iconClass","value":"bx bx-file-find","type":"label"}]},{"id":"_help_iRwzGnHPzonm","title":"Relation Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Relation Map"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_bdUJEHsAPYQR","title":"Note Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Note Map"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_HcABDtFCkbFN","title":"Render Note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Render Note"},{"name":"iconClass","value":"bx bx-extension","type":"label"}]},{"id":"_help_s1aBHPd79XYj","title":"Mermaid Diagrams","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mermaid Diagrams"},{"name":"iconClass","value":"bx bx-selection","type":"label"}],"children":[{"id":"_help_RH6yLjjWJHof","title":"ELK layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mermaid Diagrams/ELK layout"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_WWgeUaBb7UfC","title":"Syntax reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://mermaid.js.org/intro/syntax-reference.html"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_grjYqerjn243","title":"Canvas","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Canvas"},{"name":"iconClass","value":"bx bx-pen","type":"label"}]},{"id":"_help_1vHRoWCEjj0L","title":"Web View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Web View"},{"name":"iconClass","value":"bx bx-globe-alt","type":"label"}]},{"id":"_help_gBbsAeiuUxI5","title":"Mind Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mind Map"},{"name":"iconClass","value":"bx bx-sitemap","type":"label"}]},{"id":"_help_W8vYD3Q1zjCR","title":"File","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/File"},{"name":"iconClass","value":"bx bx-file-blank","type":"label"}],"children":[{"id":"_help_XJGJrpu7F9sh","title":"PDFs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/File/PDFs"},{"name":"iconClass","value":"bx bxs-file-pdf","type":"label"}]}]}]},{"id":"_help_GTwFsgaA0lCt","title":"Collections","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections"},{"name":"iconClass","value":"bx bx-book","type":"label"}],"children":[{"id":"_help_xWbu3jpNWapp","title":"Calendar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Calendar"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]},{"id":"_help_2FvYrpmOXm29","title":"Table","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Table"},{"name":"iconClass","value":"bx bx-table","type":"label"}]},{"id":"_help_CtBQqbwXDx1w","title":"Kanban Board","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Kanban Board"},{"name":"iconClass","value":"bx bx-columns","type":"label"}]},{"id":"_help_81SGnPGMk7Xc","title":"Geo Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Geo Map"},{"name":"iconClass","value":"bx bx-map-alt","type":"label"}]},{"id":"_help_zP3PMqaG71Ct","title":"Presentation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Presentation"},{"name":"iconClass","value":"bx bx-slideshow","type":"label"}]},{"id":"_help_8QqnMzx393bx","title":"Grid View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Grid View"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_mULW0Q3VojwY","title":"List View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/List View"},{"name":"iconClass","value":"bx bx-list-ul","type":"label"}]}]},{"id":"_help_BgmBlOIl72jZ","title":"Troubleshooting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting"},{"name":"iconClass","value":"bx bx-bug","type":"label"}],"children":[{"id":"_help_wy8So3yZZlH9","title":"Reporting issues","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Reporting issues"},{"name":"iconClass","value":"bx bx-bug-alt","type":"label"}]},{"id":"_help_x59R8J8KV5Bp","title":"Anonymized Database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Anonymized Database"},{"name":"iconClass","value":"bx bx-low-vision","type":"label"}]},{"id":"_help_qzNzp9LYQyPT","title":"Error logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs"},{"name":"iconClass","value":"bx bx-comment-error","type":"label"}],"children":[{"id":"_help_bnyigUA2UK7s","title":"Backend (server) logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs/Backend (server) logs"},{"name":"iconClass","value":"bx bx-server","type":"label"}]},{"id":"_help_9yEHzMyFirZR","title":"Frontend logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs/Frontend logs"},{"name":"iconClass","value":"bx bx-window-alt","type":"label"}]}]},{"id":"_help_vdlYGAcpXAgc","title":"Synchronization fails with 504 Gateway Timeout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Synchronization fails with 504"},{"name":"iconClass","value":"bx bx-error","type":"label"}]},{"id":"_help_s8alTXmpFR61","title":"Refreshing the application","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Refreshing the application"},{"name":"iconClass","value":"bx bx-refresh","type":"label"}]}]},{"id":"_help_pKK96zzmvBGf","title":"Theme development","type":"book","attributes":[{"name":"iconClass","value":"bx bx-palette","type":"label"}],"children":[{"id":"_help_7NfNr5pZpVKV","title":"Creating a custom theme","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Creating a custom theme"},{"name":"iconClass","value":"bx bxs-color","type":"label"}]},{"id":"_help_WFGzWeUK6arS","title":"Customize the Next theme","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Customize the Next theme"},{"name":"iconClass","value":"bx bx-news","type":"label"}]},{"id":"_help_WN5z4M8ASACJ","title":"Reference","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Reference"},{"name":"iconClass","value":"bx bx-book-open","type":"label"}]},{"id":"_help_AlhDUqhENtH7","title":"Custom app-wide CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Custom app-wide CSS"},{"name":"iconClass","value":"bx bxs-file-css","type":"label"}]},{"id":"_help_g1mlRoU8CsqC","title":"Creating an icon pack","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Creating an icon pack"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_tC7s2alapj8V","title":"Advanced Usage","type":"book","attributes":[{"name":"iconClass","value":"bx bx-rocket","type":"label"}],"children":[{"id":"_help_zEY4DaJG4YT5","title":"Attributes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes"},{"name":"iconClass","value":"bx bx-list-check","type":"label"}],"children":[{"id":"_help_HI6GBBIduIgv","title":"Labels","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Labels"},{"name":"iconClass","value":"bx bx-hash","type":"label"}]},{"id":"_help_Cq5X6iKQop6R","title":"Relations","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Relations"},{"name":"iconClass","value":"bx bx-transfer","type":"label"}]},{"id":"_help_bwZpz2ajCEwO","title":"Attribute Inheritance","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Attribute Inheritance"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_OFXdgB2nNk1F","title":"Promoted Attributes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Promoted Attributes"},{"name":"iconClass","value":"bx bx-table","type":"label"}]}]},{"id":"_help_KC1HB96bqqHX","title":"Templates","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Templates"},{"name":"iconClass","value":"bx bx-copy","type":"label"}]},{"id":"_help_BCkXAVs63Ttv","title":"Note Map (Link map, Tree map)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note Map (Link map, Tree map)"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_R9pX4DGra2Vt","title":"Sharing","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing"},{"name":"iconClass","value":"bx bx-share-alt","type":"label"}],"children":[{"id":"_help_Qjt68inQ2bRj","title":"Serving directly the content of a note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Serving directly the content o"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_ycBFjKrrwE9p","title":"Exporting static HTML for web publishing","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Exporting static HTML for web "},{"name":"iconClass","value":"bx bxs-file-html","type":"label"}]},{"id":"_help_sLIJ6f1dkJYW","title":"Reverse proxy configuration","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Reverse proxy configuration"},{"name":"iconClass","value":"bx bx-world","type":"label"}]}]},{"id":"_help_5668rwcirq1t","title":"Advanced Showcases","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases"},{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_l0tKav7yLHGF","title":"Day Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Day Notes"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]},{"id":"_help_R7abl2fc6Mxi","title":"Weight Tracker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Weight Tracker"},{"name":"iconClass","value":"bx bx-line-chart","type":"label"}]},{"id":"_help_xYjQUYhpbUEW","title":"Task Manager","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Task Manager"},{"name":"iconClass","value":"bx bx-calendar-check","type":"label"}]}]},{"id":"_help_J5Ex1ZrMbyJ6","title":"Custom Request Handler","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Custom Request Handler"},{"name":"iconClass","value":"bx bx-globe","type":"label"}]},{"id":"_help_d3fAXQ2diepH","title":"Custom Resource Providers","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Custom Resource Providers"},{"name":"iconClass","value":"bx bxs-file-plus","type":"label"}]},{"id":"_help_pgxEVkzLl1OP","title":"ETAPI (REST API)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/ETAPI (REST API)"},{"name":"iconClass","value":"bx bx-extension","type":"label"}],"children":[{"id":"_help_9qPsTWBorUhQ","title":"API Reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/rest-api/etapi/"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_47ZrP6FNuoG8","title":"Default Note Title","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Default Note Title"},{"name":"iconClass","value":"bx bx-edit-alt","type":"label"}]},{"id":"_help_wX4HbRucYSDD","title":"Database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database"},{"name":"iconClass","value":"bx bx-data","type":"label"}],"children":[{"id":"_help_oyIAJ9PvvwHX","title":"Manually altering the database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Manually altering the database"},{"name":"iconClass","value":"bx bxs-edit","type":"label"}],"children":[{"id":"_help_YKWqdJhzi2VY","title":"SQL Console","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Manually altering the database/SQL Console"},{"name":"iconClass","value":"bx bx-data","type":"label"}]}]},{"id":"_help_6tZeKvSHEUiB","title":"Demo Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Demo Notes"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_Gzjqa934BdH4","title":"Configuration (config.ini or environment variables)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or e"},{"name":"iconClass","value":"bx bx-cog","type":"label"}],"children":[{"id":"_help_c5xB8m4g2IY6","title":"Trilium instance","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or environment variables)/Trilium instance"},{"name":"iconClass","value":"bx bx-windows","type":"label"}]},{"id":"_help_LWtBjFej3wX3","title":"Cross-Origin Resource Sharing (CORS)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or environment variables)/Cross-Origin Resource Sharing "},{"name":"iconClass","value":"bx bx-lock","type":"label"}]}]},{"id":"_help_ivYnonVFBxbQ","title":"Bulk Actions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Bulk Actions"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_4FahAwuGTAwC","title":"Note source","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note source"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_1YeN2MzFUluU","title":"Technologies used","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used"},{"name":"iconClass","value":"bx bx-pyramid","type":"label"}],"children":[{"id":"_help_MI26XDLSAlCD","title":"CKEditor","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/CKEditor"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_N4IDkixaDG9C","title":"MindElixir","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/MindElixir"},{"name":"iconClass","value":"bx bx-sitemap","type":"label"}]},{"id":"_help_H0mM1lTxF9JI","title":"Excalidraw","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/Excalidraw"},{"name":"iconClass","value":"bx bx-pen","type":"label"}]},{"id":"_help_MQHyy2dIFgxS","title":"Leaflet","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/Leaflet"},{"name":"iconClass","value":"bx bx-map-alt","type":"label"}]}]},{"id":"_help_m1lbrzyKDaRB","title":"Note ID","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note ID"},{"name":"iconClass","value":"bx bx-hash","type":"label"}]},{"id":"_help_0vTSyvhPTAOz","title":"Internal API","type":"book","attributes":[{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_z8O2VG4ZZJD7","title":"API Reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/rest-api/internal/"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_2mUhVmZK8RF3","title":"Hidden Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Hidden Notes"},{"name":"iconClass","value":"bx bx-hide","type":"label"}]},{"id":"_help_uYF7pmepw27K","title":"Metrics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Metrics"},{"name":"iconClass","value":"bx bxs-data","type":"label"}],"children":[{"id":"_help_bOP3TB56fL1V","title":"grafana-dashboard.json","type":"doc","attributes":[{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_64ZTlUPgEPtW","title":"Safe mode","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Safe mode"},{"name":"iconClass","value":"bx bxs-virus-block","type":"label"}]},{"id":"_help_HAIOFBoYIIdO","title":"Nightly release","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Nightly release"},{"name":"iconClass","value":"bx bx-moon","type":"label"}]},{"id":"_help_ZmT9ln8XJX2o","title":"Read-only database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Read-only database"},{"name":"iconClass","value":"bx bx-book-reader","type":"label"}]}]},{"id":"_help_GBBMSlVSOIGP","title":"AI","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI"},{"name":"iconClass","value":"bx bx-bot","type":"label"}],"children":[{"id":"_help_WkM7gsEUyCXs","title":"Providers","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers"},{"name":"iconClass","value":"bx bx-select-multiple","type":"label"}],"children":[{"id":"_help_7EdTxPADv95W","title":"Ollama","type":"book","attributes":[{"name":"iconClass","value":"bx bx-message-dots","type":"label"}],"children":[{"id":"_help_vvUCN7FDkq7G","title":"Installing Ollama","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/Ollama/Installing Ollama"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_ZavFigBX9AwP","title":"OpenAI","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/OpenAI"},{"name":"iconClass","value":"bx bx-message-dots","type":"label"}]},{"id":"_help_e0lkirXEiSNc","title":"Anthropic","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/Anthropic"},{"name":"iconClass","value":"bx bx-message-dots","type":"label"}]}]}]},{"id":"_help_CdNpE2pqjmI6","title":"Scripting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting"},{"name":"iconClass","value":"bx bxs-file-js","type":"label"}],"children":[{"id":"_help_yIhgI5H7A2Sm","title":"Frontend Basics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics"},{"name":"iconClass","value":"bx bx-window","type":"label"}],"children":[{"id":"_help_MgibgPcfeuGz","title":"Custom Widgets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets"},{"name":"iconClass","value":"bx bxs-widget","type":"label"}],"children":[{"id":"_help_SynTBQiBsdYJ","title":"Widget Basics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_GhurYZjh8e1V","title":"Note context aware widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Note context aware widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_M8IppdwVHSjG","title":"Right pane widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_YNxAqkI5Kg1M","title":"Word count widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_VqGQnnPGnqAU","title":"CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/CSS"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_gMkgcLJ6jBkg","title":"Troubleshooting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Troubleshooting"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_es8OU2GuguFU","title":"Examples","type":"book","attributes":[{"name":"iconClass","value":"bx bx-code-alt","type":"label"}],"children":[{"id":"_help_TjLYAo3JMO8X","title":"\"New Task\" launcher button","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button"},{"name":"iconClass","value":"bx bx-task","type":"label"}]},{"id":"_help_7kZPMD0uFwkH","title":"Downloading responses from Google Forms","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/Downloading responses from Goo"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_DL92EjAaXT26","title":"Using promoted attributes to configure scripts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes to c"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_4Gn3psZKsfSm","title":"Launch Bar Widgets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets"},{"name":"iconClass","value":"bx bx-dock-left","type":"label"}],"children":[{"id":"_help_IPArqVfDQ4We","title":"Note Title Widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets/Note Title Widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_gcI7RPbaNSh3","title":"Analog Watch","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets/Analog Watch"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_KLsqhjaqh1QW","title":"Preact","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact"},{"name":"iconClass","value":"bx bxl-react","type":"label"}],"children":[{"id":"_help_Bqde6BvPo05g","title":"Component libraries","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Component libraries"},{"name":"iconClass","value":"bx bxs-component","type":"label"}]},{"id":"_help_ykYtbM9k3a7B","title":"Hooks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Hooks"},{"name":"iconClass","value":"bx bx-question-mark","type":"label"}]},{"id":"_help_Sg9GrCtyftZf","title":"CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/CSS"},{"name":"iconClass","value":"bx bxs-file-css","type":"label"}]},{"id":"_help_RSssb9S3xgSr","title":"Built-in components","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Built-in components"},{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_i9B4IW7b6V6z","title":"Widget showcase","type":"doc","attributes":[{"name":"iconClass","value":"bx bx-file","type":"label"}]}]}]}]},{"id":"_help_SPirpZypehBG","title":"Backend scripts","type":"book","attributes":[{"name":"iconClass","value":"bx bx-server","type":"label"}],"children":[{"id":"_help_fZ2IGYFXjkEy","title":"Server-side imports","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Backend scripts/Server-side imports"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_GPERMystNGTB","title":"Events","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Backend scripts/Events"},{"name":"iconClass","value":"bx bx-rss","type":"label"}]}]},{"id":"_help_wqXwKJl6VpNk","title":"Common concepts","type":"book","attributes":[{"name":"iconClass","value":"bx bxl-nodejs","type":"label"}],"children":[{"id":"_help_hA834UaHhSNn","title":"Script bundles","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Common concepts/Script bundles"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_GLks18SNjxmC","title":"Script API","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Script API"},{"name":"iconClass","value":"bx bx-code-curly","type":"label"}],"children":[{"id":"_help_Q2z6av6JZVWm","title":"Frontend API","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/frontend"},{"name":"iconClass","value":"bx bx-folder","type":"label"}],"enforceAttributes":true,"children":[{"id":"_help_habiZ3HU8Kw8","title":"FNote","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/frontend/interfaces/FNote.html"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_MEtfsqa5VwNi","title":"Backend API","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/backend"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true},{"id":"_help_ApVHZ8JY5ofC","title":"Day.js","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Script API/Day.js"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]}]},{"id":"_help_vElnKeDNPSVl","title":"Logging","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Logging"},{"name":"iconClass","value":"bx bx-terminal","type":"label"}]}]},{"id":"_help_Fm0j45KqyHpU","title":"Miscellaneous","type":"book","attributes":[{"name":"iconClass","value":"bx bx-info-circle","type":"label"}],"children":[{"id":"_help_WFbFXrgnDyyU","title":"Privacy Policy","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Miscellaneous/Privacy Policy"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_NcsmUYZRWEW4","title":"Patterns of personal knowledge","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Miscellaneous/Patterns of personal knowledge"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]}] \ No newline at end of file +[{"id":"_help_BOCnjTMBCoxW","title":"Feature Highlights","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Feature Highlights"},{"name":"iconClass","value":"bx bx-star","type":"label"}]},{"id":"_help_Otzi9La2YAUX","title":"Installation & Setup","type":"book","attributes":[{"name":"iconClass","value":"bx bx-cog","type":"label"}],"children":[{"id":"_help_poXkQfguuA0U","title":"Desktop Installation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation"},{"name":"iconClass","value":"bx bx-desktop","type":"label"}],"children":[{"id":"_help_nRqcgfTb97uV","title":"Using the desktop application as a server","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/Using the desktop application "},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_Rp0q8bSP6Ayl","title":"System Requirements","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/System Requirements"},{"name":"iconClass","value":"bx bx-chip","type":"label"}]},{"id":"_help_Un4wj2Mak2Ky","title":"Nix flake","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/Nix flake"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]}]},{"id":"_help_WOcw2SLH6tbX","title":"Server Installation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation"},{"name":"iconClass","value":"bx bx-server","type":"label"}],"children":[{"id":"_help_Dgg7bR3b6K9j","title":"1. Installing the server","type":"book","attributes":[{"name":"iconClass","value":"bx bx-folder","type":"label"}],"children":[{"id":"_help_3tW6mORuTHnB","title":"Packaged version for Linux","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged version for Linux"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]},{"id":"_help_rWX5eY045zbE","title":"Using Docker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Using Docker"},{"name":"iconClass","value":"bx bxl-docker","type":"label"}]},{"id":"_help_moVgBcoxE3EK","title":"On NixOS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/On NixOS"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]},{"id":"_help_J1Bb6lVlwU5T","title":"Manually","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manually"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}]},{"id":"_help_DCmT6e7clMoP","title":"Using Kubernetes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Using Kubernetes"},{"name":"iconClass","value":"bx bxl-kubernetes","type":"label"}]},{"id":"_help_klCWNks3ReaQ","title":"Multiple server instances","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Multiple server instances"},{"name":"iconClass","value":"bx bxs-user-account","type":"label"}]}]},{"id":"_help_vcjrb3VVYPZI","title":"2. Reverse proxy","type":"book","attributes":[{"name":"iconClass","value":"bx bx-folder","type":"label"}],"children":[{"id":"_help_ud6MShXL4WpO","title":"Nginx","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Nginx"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_fDLvzOx29Pfg","title":"Apache using Docker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Apache using Docker"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_LLzSMXACKhUs","title":"Trusted proxy","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Trusted proxy"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_5ERVJb9s4FRD","title":"Traefik","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Traefik"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_l2VkvOwUNfZj","title":"HTTPS (TLS)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/HTTPS (TLS)"},{"name":"iconClass","value":"bx bx-lock-alt","type":"label"}]},{"id":"_help_0hzsNCP31IAB","title":"Authentication","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Authentication"},{"name":"iconClass","value":"bx bx-user","type":"label"}]},{"id":"_help_7DAiwaf8Z7Rz","title":"Multi-Factor Authentication","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Multi-Factor Authentication"},{"name":"iconClass","value":"bx bx-stopwatch","type":"label"}]},{"id":"_help_Un4wj2Mak2Ky","title":"Nix flake","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Nix flake.clone"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_yeEaYqosGLSh","title":"Third-party cloud hosting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Third-party cloud hosting"},{"name":"iconClass","value":"bx bx-cloud","type":"label"}]},{"id":"_help_iGTnKjubbXkA","title":"System Requirements","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/System Requirements"},{"name":"iconClass","value":"bx bx-chip","type":"label"}]}]},{"id":"_help_cbkrhQjrkKrh","title":"Synchronization","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Synchronization"},{"name":"iconClass","value":"bx bx-sync","type":"label"}]},{"id":"_help_RDslemsQ6gCp","title":"Mobile Frontend","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Mobile Frontend"},{"name":"iconClass","value":"bx bx-mobile-alt","type":"label"}]},{"id":"_help_MtPxeAWVAzMg","title":"Web Clipper","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Web Clipper"},{"name":"iconClass","value":"bx bx-paperclip","type":"label"}]},{"id":"_help_n1lujUxCwipy","title":"Upgrading TriliumNext","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Upgrading TriliumNext"},{"name":"iconClass","value":"bx bx-up-arrow-alt","type":"label"}]},{"id":"_help_ODY7qQn5m2FT","title":"Backup","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Backup"},{"name":"iconClass","value":"bx bx-hdd","type":"label"}]},{"id":"_help_tAassRL4RSQL","title":"Data directory","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Data directory"},{"name":"iconClass","value":"bx bx-folder-open","type":"label"}]}]},{"id":"_help_gh7bpGYxajRS","title":"Basic Concepts and Features","type":"book","attributes":[{"name":"iconClass","value":"bx bx-help-circle","type":"label"}],"children":[{"id":"_help_Vc8PjrjAGuOp","title":"UI Elements","type":"book","attributes":[{"name":"iconClass","value":"bx bx-window-alt","type":"label"}],"children":[{"id":"_help_x0JgW8UqGXvq","title":"Vertical and horizontal layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Vertical and horizontal layout"},{"name":"iconClass","value":"bx bxs-layout","type":"label"}]},{"id":"_help_x3i7MxGccDuM","title":"Global menu","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Global menu"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_oPVyFC7WL2Lp","title":"Note Tree","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree"},{"name":"iconClass","value":"bx bxs-tree-alt","type":"label"}],"children":[{"id":"_help_YtSN43OrfzaA","title":"Note tree contextual menu","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Note tree contextual menu"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_yTjUdsOi4CIE","title":"Multiple selection","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Multiple selection"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_DvdZhoQZY9Yd","title":"Keyboard shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Keyboard shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]},{"id":"_help_wyaGBBQrl4i3","title":"Hiding the subtree","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree"},{"name":"iconClass","value":"bx bx-hide","type":"label"}]}]},{"id":"_help_BlN9DFI679QC","title":"Ribbon","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon"},{"name":"iconClass","value":"bx bx-dots-horizontal","type":"label"}]},{"id":"_help_3seOhtN8uLIY","title":"Tabs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Tabs"},{"name":"iconClass","value":"bx bx-dock-top","type":"label"}]},{"id":"_help_xYmIYSP6wE3F","title":"Launch Bar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Launch Bar"},{"name":"iconClass","value":"bx bx-sidebar","type":"label"}]},{"id":"_help_8YBEPzcpUgxw","title":"Note buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note buttons"},{"name":"iconClass","value":"bx bx-dots-vertical-rounded","type":"label"}]},{"id":"_help_4TIF1oA4VQRO","title":"Options","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Options"},{"name":"iconClass","value":"bx bx-cog","type":"label"}]},{"id":"_help_luNhaphA37EO","title":"Split View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Split View"},{"name":"iconClass","value":"bx bx-dock-right","type":"label"}]},{"id":"_help_XpOYSgsLkTJy","title":"Floating buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Floating buttons"},{"name":"iconClass","value":"bx bx-rectangle","type":"label"}]},{"id":"_help_RnaPdbciOfeq","title":"Right Sidebar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Right Sidebar"},{"name":"iconClass","value":"bx bxs-dock-right","type":"label"}]},{"id":"_help_r5JGHN99bVKn","title":"Recent Changes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Recent Changes"},{"name":"iconClass","value":"bx bx-history","type":"label"}]},{"id":"_help_ny318J39E5Z0","title":"Zoom","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Zoom"},{"name":"iconClass","value":"bx bx-zoom-in","type":"label"}]},{"id":"_help_lgKX7r3aL30x","title":"Note Tooltip","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tooltip"},{"name":"iconClass","value":"bx bx-message-detail","type":"label"}]},{"id":"_help_IjZS7iK5EXtb","title":"New Layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout"},{"name":"iconClass","value":"bx bx-layout","type":"label"}],"children":[{"id":"_help_I6p2a06hdnL6","title":"Breadcrumb","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout/Breadcrumb"},{"name":"iconClass","value":"bx bx-chevron-right","type":"label"}]},{"id":"_help_AlJ73vBCjWDw","title":"Status bar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout/Status bar"},{"name":"iconClass","value":"bx bx-dock-bottom","type":"label"}]}]}]},{"id":"_help_BFs8mudNFgCS","title":"Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes"},{"name":"iconClass","value":"bx bx-notepad","type":"label"}],"children":[{"id":"_help_p9kXRFAkwN4o","title":"Note Icons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note Icons"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_0vhv7lsOLy82","title":"Attachments","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Attachments"},{"name":"iconClass","value":"bx bx-paperclip","type":"label"}]},{"id":"_help_IakOLONlIfGI","title":"Cloning Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Cloning Notes"},{"name":"iconClass","value":"bx bx-duplicate","type":"label"}],"children":[{"id":"_help_TBwsyfadTA18","title":"Branch prefix","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Cloning Notes/Branch prefix"},{"name":"iconClass","value":"bx bx-rename","type":"label"}]}]},{"id":"_help_bwg0e8ewQMak","title":"Protected Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Protected Notes"},{"name":"iconClass","value":"bx bx-lock-alt","type":"label"}]},{"id":"_help_MKmLg5x6xkor","title":"Archived Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Archived Notes"},{"name":"iconClass","value":"bx bx-box","type":"label"}]},{"id":"_help_vZWERwf8U3nx","title":"Note Revisions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note Revisions"},{"name":"iconClass","value":"bx bx-history","type":"label"}]},{"id":"_help_aGlEvb9hyDhS","title":"Sorting Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Sorting Notes"},{"name":"iconClass","value":"bx bx-sort-up","type":"label"}]},{"id":"_help_NRnIZmSMc5sj","title":"Printing & Exporting as PDF","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF"},{"name":"iconClass","value":"bx bx-printer","type":"label"}]},{"id":"_help_CoFPLs3dRlXc","title":"Read-Only Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Read-Only Notes"},{"name":"iconClass","value":"bx bx-edit-alt","type":"label"}]},{"id":"_help_0ESUbbAxVnoK","title":"Note List","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note List"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]}]},{"id":"_help_wArbEsdSae6g","title":"Navigation","type":"book","attributes":[{"name":"iconClass","value":"bx bx-navigation","type":"label"}],"children":[{"id":"_help_kBrnXNG3Hplm","title":"Tree Concepts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Tree Concepts"},{"name":"iconClass","value":"bx bx-pyramid","type":"label"}]},{"id":"_help_MMiBEQljMQh2","title":"Note Navigation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Note Navigation"},{"name":"iconClass","value":"bx bxs-navigation","type":"label"}]},{"id":"_help_Ms1nauBra7gq","title":"Quick search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Quick search"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]},{"id":"_help_F1r9QtzQLZqm","title":"Jump to...","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Jump to"},{"name":"iconClass","value":"bx bx-send","type":"label"}]},{"id":"_help_eIg8jdvaoNNd","title":"Search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Search"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]},{"id":"_help_u3YFHC9tQlpm","title":"Bookmarks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Bookmarks"},{"name":"iconClass","value":"bx bx-bookmarks","type":"label"}]},{"id":"_help_OR8WJ7Iz9K4U","title":"Note Hoisting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Note Hoisting"},{"name":"iconClass","value":"bx bxs-chevrons-up","type":"label"}]},{"id":"_help_ZjLYv08Rp3qC","title":"Quick edit","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Quick edit"},{"name":"iconClass","value":"bx bx-edit","type":"label"}]},{"id":"_help_9sRHySam5fXb","title":"Workspaces","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Workspaces"},{"name":"iconClass","value":"bx bx-door-open","type":"label"}]},{"id":"_help_xWtq5NUHOwql","title":"Similar Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Similar Notes"},{"name":"iconClass","value":"bx bx-bar-chart","type":"label"}]},{"id":"_help_McngOG2jbUWX","title":"Search in note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Search in note"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]}]},{"id":"_help_A9Oc6YKKc65v","title":"Keyboard Shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Keyboard Shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]},{"id":"_help_Wy267RK4M69c","title":"Themes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes"},{"name":"iconClass","value":"bx bx-palette","type":"label"}],"children":[{"id":"_help_VbjZvtUek0Ln","title":"Theme Gallery","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes/Theme Gallery"},{"name":"iconClass","value":"bx bx-book-reader","type":"label"}]},{"id":"_help_gOKqSJgXLcIj","title":"Icon Packs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_mHbBMPDPkVV5","title":"Import & Export","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export"},{"name":"iconClass","value":"bx bx-import","type":"label"}],"children":[{"id":"_help_Oau6X9rCuegd","title":"Markdown","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Markdown"},{"name":"iconClass","value":"bx bxl-markdown","type":"label"}],"children":[{"id":"_help_rJ9grSgoExl9","title":"Supported syntax","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Markdown/Supported syntax"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}]}]},{"id":"_help_syuSEKf2rUGr","title":"Evernote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Evernote"},{"name":"iconClass","value":"bx bx-window-open","type":"label"}]},{"id":"_help_GnhlmrATVqcH","title":"OneNote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/OneNote"},{"name":"iconClass","value":"bx bx-window-open","type":"label"}]}]},{"id":"_help_rC3pL2aptaRE","title":"Zen mode","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Zen mode"},{"name":"iconClass","value":"bx bxs-yin-yang","type":"label"}]}]},{"id":"_help_s3YCWHBfmYuM","title":"Quick Start","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Quick Start"},{"name":"iconClass","value":"bx bx-run","type":"label"}]},{"id":"_help_i6dbnitykE5D","title":"FAQ","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/FAQ"},{"name":"iconClass","value":"bx bx-question-mark","type":"label"}]},{"id":"_help_KSZ04uQ2D1St","title":"Note Types","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types"},{"name":"iconClass","value":"bx bx-edit","type":"label"}],"children":[{"id":"_help_iPIMuisry3hd","title":"Text","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text"},{"name":"iconClass","value":"bx bx-note","type":"label"}],"children":[{"id":"_help_NwBbFdNZ9h7O","title":"Block quotes & admonitions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Block quotes & admonitions"},{"name":"iconClass","value":"bx bx-info-circle","type":"label"}]},{"id":"_help_oSuaNgyyKnhu","title":"Bookmarks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Bookmarks"},{"name":"iconClass","value":"bx bx-bookmark","type":"label"}]},{"id":"_help_veGu4faJErEM","title":"Content language & Right-to-left support","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Content language & Right-to-le"},{"name":"iconClass","value":"bx bx-align-right","type":"label"}]},{"id":"_help_2x0ZAX9ePtzV","title":"Cut to subnote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Cut to subnote"},{"name":"iconClass","value":"bx bx-cut","type":"label"}]},{"id":"_help_UYuUB1ZekNQU","title":"Developer-specific formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Developer-specific formatting"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}],"children":[{"id":"_help_QxEyIjRBizuC","title":"Code blocks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Developer-specific formatting/Code blocks"},{"name":"iconClass","value":"bx bx-code","type":"label"}]}]},{"id":"_help_AgjCISero73a","title":"Footnotes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Footnotes"},{"name":"iconClass","value":"bx bx-bracket","type":"label"}]},{"id":"_help_nRhnJkTT8cPs","title":"Formatting toolbar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Formatting toolbar"},{"name":"iconClass","value":"bx bx-text","type":"label"}]},{"id":"_help_Gr6xFaF6ioJ5","title":"General formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/General formatting"},{"name":"iconClass","value":"bx bx-bold","type":"label"}]},{"id":"_help_AxshuNRegLAv","title":"Highlights list","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Highlights list"},{"name":"iconClass","value":"bx bx-highlight","type":"label"}]},{"id":"_help_mT0HEkOsz6i1","title":"Images","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Images"},{"name":"iconClass","value":"bx bx-image-alt","type":"label"}],"children":[{"id":"_help_0Ofbk1aSuVRu","title":"Image references","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Images/Image references"},{"name":"iconClass","value":"bx bxs-file-image","type":"label"}]}]},{"id":"_help_nBAXQFj20hS1","title":"Include Note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Include Note"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_CohkqWQC1iBv","title":"Insert buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Insert buttons"},{"name":"iconClass","value":"bx bx-plus","type":"label"}]},{"id":"_help_oiVPnW8QfnvS","title":"Keyboard shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Keyboard shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]},{"id":"_help_QEAPj01N5f7w","title":"Links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links"},{"name":"iconClass","value":"bx bx-link-alt","type":"label"}],"children":[{"id":"_help_3IDVtesTQ8ds","title":"External links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links/External links"},{"name":"iconClass","value":"bx bx-link-external","type":"label"}]},{"id":"_help_hrZ1D00cLbal","title":"Internal (reference) links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links/Internal (reference) links"},{"name":"iconClass","value":"bx bx-link","type":"label"}]}]},{"id":"_help_S6Xx8QIWTV66","title":"Lists","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Lists"},{"name":"iconClass","value":"bx bx-list-ul","type":"label"}]},{"id":"_help_QrtTYPmdd1qq","title":"Markdown-like formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Markdown-like formatting"},{"name":"iconClass","value":"bx bxl-markdown","type":"label"}]},{"id":"_help_YfYAtQBcfo5V","title":"Math Equations","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Math Equations"},{"name":"iconClass","value":"bx bx-math","type":"label"}]},{"id":"_help_dEHYtoWWi8ct","title":"Other features","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Other features"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_gLt3vA97tMcp","title":"Premium features","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features"},{"name":"iconClass","value":"bx bx-star","type":"label"}],"children":[{"id":"_help_ZlN4nump6EbW","title":"Slash Commands","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Slash Commands"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_pwc194wlRzcH","title":"Text Snippets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Text Snippets"},{"name":"iconClass","value":"bx bx-align-left","type":"label"}]},{"id":"_help_5wZallV2Qo1t","title":"Format Painter","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Format Painter"},{"name":"iconClass","value":"bx bxs-paint-roll","type":"label"}]}]},{"id":"_help_BFvAtE74rbP6","title":"Table of contents","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Table of contents"},{"name":"iconClass","value":"bx bx-heading","type":"label"}]},{"id":"_help_NdowYOC1GFKS","title":"Tables","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Tables"},{"name":"iconClass","value":"bx bx-table","type":"label"}]}]},{"id":"_help_6f9hih2hXXZk","title":"Code","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Code"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_m523cpzocqaD","title":"Saved Search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Saved Search"},{"name":"iconClass","value":"bx bx-file-find","type":"label"}]},{"id":"_help_iRwzGnHPzonm","title":"Relation Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Relation Map"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_bdUJEHsAPYQR","title":"Note Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Note Map"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_HcABDtFCkbFN","title":"Render Note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Render Note"},{"name":"iconClass","value":"bx bx-extension","type":"label"}]},{"id":"_help_s1aBHPd79XYj","title":"Mermaid Diagrams","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mermaid Diagrams"},{"name":"iconClass","value":"bx bx-selection","type":"label"}],"children":[{"id":"_help_RH6yLjjWJHof","title":"ELK layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mermaid Diagrams/ELK layout"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_WWgeUaBb7UfC","title":"Syntax reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://mermaid.js.org/intro/syntax-reference.html"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_grjYqerjn243","title":"Canvas","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Canvas"},{"name":"iconClass","value":"bx bx-pen","type":"label"}]},{"id":"_help_1vHRoWCEjj0L","title":"Web View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Web View"},{"name":"iconClass","value":"bx bx-globe-alt","type":"label"}]},{"id":"_help_gBbsAeiuUxI5","title":"Mind Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mind Map"},{"name":"iconClass","value":"bx bx-sitemap","type":"label"}]},{"id":"_help_W8vYD3Q1zjCR","title":"File","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/File"},{"name":"iconClass","value":"bx bx-file-blank","type":"label"}],"children":[{"id":"_help_XJGJrpu7F9sh","title":"PDFs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/File/PDFs"},{"name":"iconClass","value":"bx bxs-file-pdf","type":"label"}]}]}]},{"id":"_help_GTwFsgaA0lCt","title":"Collections","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections"},{"name":"iconClass","value":"bx bx-book","type":"label"}],"children":[{"id":"_help_xWbu3jpNWapp","title":"Calendar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Calendar"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]},{"id":"_help_2FvYrpmOXm29","title":"Table","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Table"},{"name":"iconClass","value":"bx bx-table","type":"label"}]},{"id":"_help_CtBQqbwXDx1w","title":"Kanban Board","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Kanban Board"},{"name":"iconClass","value":"bx bx-columns","type":"label"}]},{"id":"_help_81SGnPGMk7Xc","title":"Geo Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Geo Map"},{"name":"iconClass","value":"bx bx-map-alt","type":"label"}]},{"id":"_help_zP3PMqaG71Ct","title":"Presentation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Presentation"},{"name":"iconClass","value":"bx bx-slideshow","type":"label"}]},{"id":"_help_8QqnMzx393bx","title":"Grid View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Grid View"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_mULW0Q3VojwY","title":"List View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/List View"},{"name":"iconClass","value":"bx bx-list-ul","type":"label"}]}]},{"id":"_help_BgmBlOIl72jZ","title":"Troubleshooting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting"},{"name":"iconClass","value":"bx bx-bug","type":"label"}],"children":[{"id":"_help_wy8So3yZZlH9","title":"Reporting issues","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Reporting issues"},{"name":"iconClass","value":"bx bx-bug-alt","type":"label"}]},{"id":"_help_x59R8J8KV5Bp","title":"Anonymized Database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Anonymized Database"},{"name":"iconClass","value":"bx bx-low-vision","type":"label"}]},{"id":"_help_qzNzp9LYQyPT","title":"Error logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs"},{"name":"iconClass","value":"bx bx-comment-error","type":"label"}],"children":[{"id":"_help_bnyigUA2UK7s","title":"Backend (server) logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs/Backend (server) logs"},{"name":"iconClass","value":"bx bx-server","type":"label"}]},{"id":"_help_9yEHzMyFirZR","title":"Frontend logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs/Frontend logs"},{"name":"iconClass","value":"bx bx-window-alt","type":"label"}]}]},{"id":"_help_vdlYGAcpXAgc","title":"Synchronization fails with 504 Gateway Timeout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Synchronization fails with 504"},{"name":"iconClass","value":"bx bx-error","type":"label"}]},{"id":"_help_s8alTXmpFR61","title":"Refreshing the application","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Refreshing the application"},{"name":"iconClass","value":"bx bx-refresh","type":"label"}]}]},{"id":"_help_pKK96zzmvBGf","title":"Theme development","type":"book","attributes":[{"name":"iconClass","value":"bx bx-palette","type":"label"}],"children":[{"id":"_help_7NfNr5pZpVKV","title":"Creating a custom theme","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Creating a custom theme"},{"name":"iconClass","value":"bx bxs-color","type":"label"}]},{"id":"_help_WFGzWeUK6arS","title":"Customize the Next theme","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Customize the Next theme"},{"name":"iconClass","value":"bx bx-news","type":"label"}]},{"id":"_help_WN5z4M8ASACJ","title":"Reference","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Reference"},{"name":"iconClass","value":"bx bx-book-open","type":"label"}]},{"id":"_help_AlhDUqhENtH7","title":"Custom app-wide CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Custom app-wide CSS"},{"name":"iconClass","value":"bx bxs-file-css","type":"label"}]},{"id":"_help_g1mlRoU8CsqC","title":"Creating an icon pack","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Creating an icon pack"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_tC7s2alapj8V","title":"Advanced Usage","type":"book","attributes":[{"name":"iconClass","value":"bx bx-rocket","type":"label"}],"children":[{"id":"_help_zEY4DaJG4YT5","title":"Attributes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes"},{"name":"iconClass","value":"bx bx-list-check","type":"label"}],"children":[{"id":"_help_HI6GBBIduIgv","title":"Labels","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Labels"},{"name":"iconClass","value":"bx bx-hash","type":"label"}]},{"id":"_help_Cq5X6iKQop6R","title":"Relations","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Relations"},{"name":"iconClass","value":"bx bx-transfer","type":"label"}]},{"id":"_help_bwZpz2ajCEwO","title":"Attribute Inheritance","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Attribute Inheritance"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_OFXdgB2nNk1F","title":"Promoted Attributes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Promoted Attributes"},{"name":"iconClass","value":"bx bx-table","type":"label"}]}]},{"id":"_help_KC1HB96bqqHX","title":"Templates","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Templates"},{"name":"iconClass","value":"bx bx-copy","type":"label"}]},{"id":"_help_BCkXAVs63Ttv","title":"Note Map (Link map, Tree map)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note Map (Link map, Tree map)"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_R9pX4DGra2Vt","title":"Sharing","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing"},{"name":"iconClass","value":"bx bx-share-alt","type":"label"}],"children":[{"id":"_help_Qjt68inQ2bRj","title":"Serving directly the content of a note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Serving directly the content o"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_ycBFjKrrwE9p","title":"Exporting static HTML for web publishing","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Exporting static HTML for web "},{"name":"iconClass","value":"bx bxs-file-html","type":"label"}]},{"id":"_help_sLIJ6f1dkJYW","title":"Reverse proxy configuration","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Reverse proxy configuration"},{"name":"iconClass","value":"bx bx-world","type":"label"}]}]},{"id":"_help_5668rwcirq1t","title":"Advanced Showcases","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases"},{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_l0tKav7yLHGF","title":"Day Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Day Notes"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]},{"id":"_help_R7abl2fc6Mxi","title":"Weight Tracker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Weight Tracker"},{"name":"iconClass","value":"bx bx-line-chart","type":"label"}]},{"id":"_help_xYjQUYhpbUEW","title":"Task Manager","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Task Manager"},{"name":"iconClass","value":"bx bx-calendar-check","type":"label"}]}]},{"id":"_help_J5Ex1ZrMbyJ6","title":"Custom Request Handler","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Custom Request Handler"},{"name":"iconClass","value":"bx bx-globe","type":"label"}]},{"id":"_help_d3fAXQ2diepH","title":"Custom Resource Providers","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Custom Resource Providers"},{"name":"iconClass","value":"bx bxs-file-plus","type":"label"}]},{"id":"_help_pgxEVkzLl1OP","title":"ETAPI (REST API)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/ETAPI (REST API)"},{"name":"iconClass","value":"bx bx-extension","type":"label"}],"children":[{"id":"_help_9qPsTWBorUhQ","title":"API Reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/rest-api/etapi/"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_47ZrP6FNuoG8","title":"Default Note Title","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Default Note Title"},{"name":"iconClass","value":"bx bx-edit-alt","type":"label"}]},{"id":"_help_wX4HbRucYSDD","title":"Database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database"},{"name":"iconClass","value":"bx bx-data","type":"label"}],"children":[{"id":"_help_oyIAJ9PvvwHX","title":"Manually altering the database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Manually altering the database"},{"name":"iconClass","value":"bx bxs-edit","type":"label"}],"children":[{"id":"_help_YKWqdJhzi2VY","title":"SQL Console","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Manually altering the database/SQL Console"},{"name":"iconClass","value":"bx bx-data","type":"label"}]}]},{"id":"_help_6tZeKvSHEUiB","title":"Demo Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Demo Notes"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_Gzjqa934BdH4","title":"Configuration (config.ini or environment variables)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or e"},{"name":"iconClass","value":"bx bx-cog","type":"label"}],"children":[{"id":"_help_c5xB8m4g2IY6","title":"Trilium instance","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or environment variables)/Trilium instance"},{"name":"iconClass","value":"bx bx-windows","type":"label"}]},{"id":"_help_LWtBjFej3wX3","title":"Cross-Origin Resource Sharing (CORS)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or environment variables)/Cross-Origin Resource Sharing "},{"name":"iconClass","value":"bx bx-lock","type":"label"}]}]},{"id":"_help_ivYnonVFBxbQ","title":"Bulk Actions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Bulk Actions"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_4FahAwuGTAwC","title":"Note source","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note source"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_1YeN2MzFUluU","title":"Technologies used","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used"},{"name":"iconClass","value":"bx bx-pyramid","type":"label"}],"children":[{"id":"_help_MI26XDLSAlCD","title":"CKEditor","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/CKEditor"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_N4IDkixaDG9C","title":"MindElixir","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/MindElixir"},{"name":"iconClass","value":"bx bx-sitemap","type":"label"}]},{"id":"_help_H0mM1lTxF9JI","title":"Excalidraw","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/Excalidraw"},{"name":"iconClass","value":"bx bx-pen","type":"label"}]},{"id":"_help_MQHyy2dIFgxS","title":"Leaflet","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/Leaflet"},{"name":"iconClass","value":"bx bx-map-alt","type":"label"}]}]},{"id":"_help_m1lbrzyKDaRB","title":"Note ID","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note ID"},{"name":"iconClass","value":"bx bx-hash","type":"label"}]},{"id":"_help_0vTSyvhPTAOz","title":"Internal API","type":"book","attributes":[{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_z8O2VG4ZZJD7","title":"API Reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/rest-api/internal/"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_2mUhVmZK8RF3","title":"Hidden Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Hidden Notes"},{"name":"iconClass","value":"bx bx-hide","type":"label"}]},{"id":"_help_uYF7pmepw27K","title":"Metrics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Metrics"},{"name":"iconClass","value":"bx bxs-data","type":"label"}],"children":[{"id":"_help_bOP3TB56fL1V","title":"grafana-dashboard.json","type":"doc","attributes":[{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_64ZTlUPgEPtW","title":"Safe mode","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Safe mode"},{"name":"iconClass","value":"bx bxs-virus-block","type":"label"}]},{"id":"_help_HAIOFBoYIIdO","title":"Nightly release","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Nightly release"},{"name":"iconClass","value":"bx bx-moon","type":"label"}]},{"id":"_help_ZmT9ln8XJX2o","title":"Read-only database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Read-only database"},{"name":"iconClass","value":"bx bx-book-reader","type":"label"}]}]},{"id":"_help_GBBMSlVSOIGP","title":"AI","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI"},{"name":"iconClass","value":"bx bx-bot","type":"label"}],"children":[{"id":"_help_WkM7gsEUyCXs","title":"Providers","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers"},{"name":"iconClass","value":"bx bx-select-multiple","type":"label"}],"children":[{"id":"_help_7EdTxPADv95W","title":"Ollama","type":"book","attributes":[{"name":"iconClass","value":"bx bx-message-dots","type":"label"}],"children":[{"id":"_help_vvUCN7FDkq7G","title":"Installing Ollama","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/Ollama/Installing Ollama"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_ZavFigBX9AwP","title":"OpenAI","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/OpenAI"},{"name":"iconClass","value":"bx bx-message-dots","type":"label"}]},{"id":"_help_e0lkirXEiSNc","title":"Anthropic","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/Anthropic"},{"name":"iconClass","value":"bx bx-message-dots","type":"label"}]}]}]},{"id":"_help_CdNpE2pqjmI6","title":"Scripting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting"},{"name":"iconClass","value":"bx bxs-file-js","type":"label"}],"children":[{"id":"_help_yIhgI5H7A2Sm","title":"Frontend Basics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics"},{"name":"iconClass","value":"bx bx-window","type":"label"}],"children":[{"id":"_help_MgibgPcfeuGz","title":"Custom Widgets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets"},{"name":"iconClass","value":"bx bxs-widget","type":"label"}],"children":[{"id":"_help_SynTBQiBsdYJ","title":"Widget Basics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_GhurYZjh8e1V","title":"Note context aware widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Note context aware widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_M8IppdwVHSjG","title":"Right pane widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_YNxAqkI5Kg1M","title":"Word count widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_VqGQnnPGnqAU","title":"CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/CSS"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_gMkgcLJ6jBkg","title":"Troubleshooting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Troubleshooting"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_es8OU2GuguFU","title":"Examples","type":"book","attributes":[{"name":"iconClass","value":"bx bx-code-alt","type":"label"}],"children":[{"id":"_help_TjLYAo3JMO8X","title":"\"New Task\" launcher button","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button"},{"name":"iconClass","value":"bx bx-task","type":"label"}]},{"id":"_help_7kZPMD0uFwkH","title":"Downloading responses from Google Forms","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/Downloading responses from Goo"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_DL92EjAaXT26","title":"Using promoted attributes to configure scripts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes to c"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_4Gn3psZKsfSm","title":"Launch Bar Widgets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets"},{"name":"iconClass","value":"bx bx-dock-left","type":"label"}],"children":[{"id":"_help_IPArqVfDQ4We","title":"Note Title Widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets/Note Title Widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_gcI7RPbaNSh3","title":"Analog Watch","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets/Analog Watch"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_KLsqhjaqh1QW","title":"Preact","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact"},{"name":"iconClass","value":"bx bxl-react","type":"label"}],"children":[{"id":"_help_Bqde6BvPo05g","title":"Component libraries","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Component libraries"},{"name":"iconClass","value":"bx bxs-component","type":"label"}]},{"id":"_help_ykYtbM9k3a7B","title":"Hooks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Hooks"},{"name":"iconClass","value":"bx bx-question-mark","type":"label"}]},{"id":"_help_Sg9GrCtyftZf","title":"CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/CSS"},{"name":"iconClass","value":"bx bxs-file-css","type":"label"}]},{"id":"_help_RSssb9S3xgSr","title":"Built-in components","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Built-in components"},{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_i9B4IW7b6V6z","title":"Widget showcase","type":"doc","attributes":[{"name":"iconClass","value":"bx bx-file","type":"label"}]}]}]}]},{"id":"_help_SPirpZypehBG","title":"Backend scripts","type":"book","attributes":[{"name":"iconClass","value":"bx bx-server","type":"label"}],"children":[{"id":"_help_fZ2IGYFXjkEy","title":"Server-side imports","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Backend scripts/Server-side imports"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_GPERMystNGTB","title":"Events","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Backend scripts/Events"},{"name":"iconClass","value":"bx bx-rss","type":"label"}]}]},{"id":"_help_wqXwKJl6VpNk","title":"Common concepts","type":"book","attributes":[{"name":"iconClass","value":"bx bxl-nodejs","type":"label"}],"children":[{"id":"_help_hA834UaHhSNn","title":"Script bundles","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Common concepts/Script bundles"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_GLks18SNjxmC","title":"Script API","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Script API"},{"name":"iconClass","value":"bx bx-code-curly","type":"label"}],"children":[{"id":"_help_Q2z6av6JZVWm","title":"Frontend API","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/frontend"},{"name":"iconClass","value":"bx bx-folder","type":"label"}],"enforceAttributes":true,"children":[{"id":"_help_habiZ3HU8Kw8","title":"FNote","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/frontend/interfaces/FNote.html"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_MEtfsqa5VwNi","title":"Backend API","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/backend"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true},{"id":"_help_ApVHZ8JY5ofC","title":"Day.js","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Script API/Day.js"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]}]},{"id":"_help_vElnKeDNPSVl","title":"Logging","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Logging"},{"name":"iconClass","value":"bx bx-terminal","type":"label"}]}]},{"id":"_help_Fm0j45KqyHpU","title":"Miscellaneous","type":"book","attributes":[{"name":"iconClass","value":"bx bx-info-circle","type":"label"}],"children":[{"id":"_help_WFbFXrgnDyyU","title":"Privacy Policy","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Miscellaneous/Privacy Policy"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_NcsmUYZRWEW4","title":"Patterns of personal knowledge","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Miscellaneous/Patterns of personal knowledge"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]}] \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/1_Hiding the subtree_image.png b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/1_Hiding the subtree_image.png new file mode 100644 index 000000000..44f0bbe51 Binary files /dev/null and b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/1_Hiding the subtree_image.png differ diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree.html new file mode 100644 index 000000000..c818f26dd --- /dev/null +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree.html @@ -0,0 +1,95 @@ +
    + +
    An example of a collection with a relatively large number of children + that are hidden from the tree.
    +
    +

    The tree works well when the notes are structured in a hierarchy so that + the number of items stays small. When a note has a large number of notes + (in the order of thousands or tens of thousands), two problems arise:

    +
      +
    • Navigating between notes becomes cumbersome and the tree itself gets cluttered + with a large amount of notes.
    • +
    • The large amount of notes can slow down the application considerably.
    • +
    +

    Since v0.102.0, Trilium allows the tree to hide the child notes of particular + notes. This works for both Collections and + normal notes.

    +

    Interaction

    +

    When the subtree of a note is hidden, there are a few subtle changes:

    +
      +
    • To indicate that the subtree is hidden, the note will not have an expand + button and it will display the number of children to the right.
    • +
    • It's not possible to add a new note directly from the tree. +
        +
      • For Collections, + it's best to use the built-in mechanism to create notes (for example by + creating a new point on a geo-map, or by adding a new row in a table).
      • +
      • For normal notes, it's still possible to create children via other means + such as using the Internal (reference) links system.
      • +
      +
    • +
    • Notes can be dragged from outside the note, case in which they will be + cloned into it. +
        +
      • Instead of switching to the child notes that were copied, the parent note + is highlighted instead.
      • +
      • A notification will indicate this behavior.
      • +
      +
    • +
    • Similarly, features such as cut/copy and then paste into the note will + also work.
    • +
    +

    Spotlighting

    +
    + +
    +

    Even if the subtree of a note is hidden, if a child note manages to become + active, it will still appear inside the tree in a special state called spotlighted.

    +

    During this state, the note remains under its normal hierarchy, so that + its easy to tell its location. In addition, this means that:

    +
      +
    • The note position is clearly visible when using the Search.
    • +
    • The note can still be operated on from the tree, such as adding a  + Branch prefix or moving it outside the collection.
    • +
    +

    The note appears in italics to indicate its temporary display. When switching + to another note, the spotlighted note will disappear.

    + +

    Working with collections

    +

    By default, some of the Collections will + automatically hide their child notes, for example the Kanban Board or + the Table.

    +

    The reasoning behind this is that collections are generally opaque to + the rest of the notes and they can generate a large amount of sub-notes + since they intentionally lack structure (in order to allow easy swapping + between views).

    +

    Some types of collections have the child notes intentionally shown, for + example the legacy ones (Grid and List), but also the Presentation which + requires the tree structure in order to organize and edit the slides.

    +

    To toggle this behavior:

    +
      +
    • In the New Layout, + press the Options button underneath the title and uncheck Hide child notes in tree.
    • +
    • Right click the collection note in the Note Tree and + select AdvancedShow subtree.
    • +
    +

    Working with normal notes

    +

    It's possible to hide the subtree for normal notes as well, not just collections. + To do so, right click the note in the Note Tree and + select AdvancedHide subtree. +

    \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree_image.png b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree_image.png new file mode 100644 index 000000000..7b75834e9 Binary files /dev/null and b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree_image.png differ diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/FAQ.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/FAQ.html index dcba27666..290fb0c6c 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/FAQ.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/FAQ.html @@ -47,7 +47,7 @@ href="#root/_help_tAassRL4RSQL">data directoryin the TRILIUM_DATA_DIR environment variable and separate port on TRILIUM_PORT environment variable. How to do that depends on the platform, in Unix-based systems - you can achieve that by running command such as this:

    TRILIUM_DATA_DIR=/home/me/path/to/data/dir TRILIUM_PORT=12345 trilium 
    + you can achieve that by running command such as this:

    TRILIUM_DATA_DIR=/home/me/path/to/data/dir TRILIUM_PORT=12345 trilium 

    You can save this command into a .sh script file or make an alias. Do this similarly for a second instance with different data directory and port.

    diff --git a/apps/server/src/services/hidden_subtree_templates.ts b/apps/server/src/services/hidden_subtree_templates.ts index 7f5710776..55999824c 100644 --- a/apps/server/src/services/hidden_subtree_templates.ts +++ b/apps/server/src/services/hidden_subtree_templates.ts @@ -1,7 +1,12 @@ -import { HiddenSubtreeItem } from "@triliumnext/commons"; +import { HiddenSubtreeAttribute, HiddenSubtreeItem } from "@triliumnext/commons"; import { t } from "i18next"; export default function buildHiddenSubtreeTemplates() { + const hideSubtreeAttributes: HiddenSubtreeAttribute = { + name: "subtreeHidden", + type: "label" + }; + const templates: HiddenSubtreeItem = { id: "_templates", title: t("hidden_subtree_templates.built-in-templates"), @@ -93,6 +98,7 @@ export default function buildHiddenSubtreeTemplates() { name: "hidePromotedAttributes", type: "label" }, + hideSubtreeAttributes, { name: "label:startDate", type: "label", @@ -133,6 +139,7 @@ export default function buildHiddenSubtreeTemplates() { name: "collection", type: "label" }, + hideSubtreeAttributes, { name: "viewType", type: "label", @@ -163,6 +170,7 @@ export default function buildHiddenSubtreeTemplates() { name: "hidePromotedAttributes", type: "label" }, + hideSubtreeAttributes, { name: "label:geolocation", type: "label", @@ -194,6 +202,7 @@ export default function buildHiddenSubtreeTemplates() { name: "hidePromotedAttributes", type: "label" }, + hideSubtreeAttributes, { name: "label:status", type: "label", diff --git a/apps/website/src/translations/es/translation.json b/apps/website/src/translations/es/translation.json index 112ba4ded..462078049 100644 --- a/apps/website/src/translations/es/translation.json +++ b/apps/website/src/translations/es/translation.json @@ -115,7 +115,7 @@ }, "social_buttons": { "github": "GitHub", - "github_discussions": "GitHub Discussions", + "github_discussions": "Discusiones de GitHub", "matrix": "Matrix", "reddit": "Reddit" }, diff --git a/apps/website/src/translations/hi/translation.json b/apps/website/src/translations/hi/translation.json index 00e6ce62d..d67f0d026 100644 --- a/apps/website/src/translations/hi/translation.json +++ b/apps/website/src/translations/hi/translation.json @@ -6,7 +6,9 @@ }, "hero_section": { "title": "अपने विचारों को व्यवस्थित करें। अपना व्यक्तिगत नॉलेज बेस बनाएं।", - "screenshot_alt": "ट्रिलियम नोट्स डेस्कटॉप एप्लिकेशन का स्क्रीनशॉट" + "screenshot_alt": "ट्रिलियम नोट्स डेस्कटॉप एप्लिकेशन का स्क्रीनशॉट", + "get_started": "शुरू करें", + "github": "गिटहब" }, "organization_benefits": { "note_structure_title": "नोट संरचना", @@ -26,5 +28,67 @@ "collections": { "calendar_title": "कैलेंडर", "table_title": "टेबल" + }, + "download_now": { + "linux_small": "लिनक्स के लिए", + "more_platforms": "अधिक प्लेटफॉर्म और सर्वर सेटअप" + }, + "header": { + "get-started": "शुरू करें", + "support-us": "हमें सपोर्ट करें" + }, + "social_buttons": { + "github": "गिटहब", + "matrix": "मैट्रिक्स", + "reddit": "रेडिट" + }, + "support_us": { + "title": "हमें सपोर्ट करें" + }, + "404": { + "description": "आप जो पेज खोज रहे थे वह नहीं मिल पाया। शायद वह डिलीट हो चुका है या यूआरएल (URL) गलत है।" + }, + "download_helper_desktop_windows": { + "title_x64": "Windows 64-bit", + "title_arm64": "ARM पर Windows", + "quick_start": "Winget द्वारा इंस्टॉल करने के लिए:", + "download_exe": "इंस्टॉलर (.exe) डाउनलोड करें", + "download_zip": "पोर्टेबल (.zip)" + }, + "download_helper_desktop_linux": { + "title_x64": "Linux 64-bit", + "title_arm64": "ARM पर लिनक्स", + "download_deb": ".deb", + "download_rpm": ".rpm", + "download_flatpak": ".flatpak", + "download_zip": "पोर्टेबल (.zip)", + "download_nixpkgs": "nixpkgs" + }, + "download_helper_desktop_macos": { + "title_x64": "Intel के लिए macOS", + "title_arm64": "Apple Silicon के लिए macOS", + "description_x64": "macOS Monterey या उसके बाद के वर्ज़न पर चलने वाले Intel-आधारित Macs के लिए।", + "description_arm64": "Apple Silicon Macs के लिए, जैसे कि M1 और M2 चिप्स वाले मॉडल।", + "quick_start": "Homebrew द्वारा इंस्टॉल करने के लिए:", + "download_dmg": "इंस्टॉलर (.dmg) डाउनलोड करें", + "download_homebrew_cask": "Homebrew Cask", + "download_zip": "पोर्टेबल (.zip)" + }, + "download_helper_server_docker": { + "title": "Docker द्वारा सेल्फ-होस्टेड", + "description": "Docker कंटेनर का उपयोग करके Windows, Linux या macOS पर आसानी से डिप्लॉय करें।", + "download_ghcr": "ghcr.io" + }, + "download_helper_server_linux": { + "title": "Linux पर सेल्फ-होस्टेड", + "description": "ट्रिलियम नोट्स को अपने खुद के सर्वर या VPS पर डिप्लॉय करें, जो अधिकांश डिस्ट्रीब्यूशनो के साथ कम्पेटिबल है।", + "download_tar_x64": "x64 (.tar.xz)", + "download_tar_arm64": "ARM (.tar.xz)", + "download_nixos": "NixOS मॉड्यूल" + }, + "download_helper_server_hosted": { + "title": "पेड होस्टिंग", + "download_pikapod": "PikaPods पर सेटअप करें", + "download_triliumcc": "वैकल्पिक रूप से trilium.cc देखें" } } diff --git a/docs/README-de.md b/docs/README-de.md index 43ed6d320..3636ec91e 100644 --- a/docs/README-de.md +++ b/docs/README-de.md @@ -96,8 +96,8 @@ Unsere Dokumentation ist verfügbar in mehreren Formaten: für eine sicherere Anmeldung * [Synchronisierung](https://docs.triliumnotes.org/user-guide/setup/synchronization) mit einem selbst gehosteten Synchronisierungsserver - * there are [3rd party services for hosting synchronisation - server](https://docs.triliumnotes.org/user-guide/setup/server/cloud-hosting) + * Es gibt [Drittanbieter-Dienste für das Hosting von + Synchronisationsservern](https://docs.triliumnotes.org/user-guide/setup/server/cloud-hosting) * [Freigabe](https://docs.triliumnotes.org/user-guide/advanced-usage/sharing) (Veröffentlichung) von Notizen im öffentlichen Internet * Starke @@ -105,10 +105,10 @@ Unsere Dokumentation ist verfügbar in mehreren Formaten: mit Granularität pro Notiz * Skizzieren von Diagrammen basierend auf [Excalidraw](https://excalidraw.com/) (Notiztyp „Canvas“) -* [Relation - maps](https://docs.triliumnotes.org/user-guide/note-types/relation-map) and - [note/link maps](https://docs.triliumnotes.org/user-guide/note-types/note-map) - for visualizing notes and their relations +* [Beziehungskarten](https://docs.triliumnotes.org/user-guide/note-types/relation-map) + und + [Notiz-/Link-Karten](https://docs.triliumnotes.org/user-guide/note-types/note-map) + zur Visualisierung von Notizen und ihren Beziehungen * Mindmaps, basierend auf [Mind Elixir](https://docs.mind-elixir.com/) * [Geokarten](https://docs.triliumnotes.org/user-guide/collections/geomap) mit Standortmarkierungen und GPX-Tracks @@ -132,8 +132,8 @@ Unsere Dokumentation ist verfügbar in mehreren Formaten: einfachen Speichern von Webinhalten * Anpassbare Benutzeroberfläche (Seitenleisten-Schaltflächen, benutzerdefinierte Widgets, ...) -* [Metrics](https://docs.triliumnotes.org/user-guide/advanced-usage/metrics), - along with a Grafana Dashboard. +* [Metriken](https://docs.triliumnotes.org/user-guide/advanced-usage/metrics) + zusammen mit einem Grafana-Dashboard. ✨ Weitere Informationen zu TriliumNext findet man in den folgenden Ressourcen/Communities von Drittanbietern: diff --git a/docs/README-hi.md b/docs/README-hi.md index c47ebdb11..b4dd0da63 100644 --- a/docs/README-hi.md +++ b/docs/README-hi.md @@ -74,13 +74,13 @@ Our documentation is available in multiple formats: * Rich WYSIWYG note editor including e.g. tables, images and [math](https://docs.triliumnotes.org/user-guide/note-types/text) with markdown [autoformat](https://docs.triliumnotes.org/user-guide/note-types/text/markdown-formatting) -* Support for editing [notes with source - code](https://docs.triliumnotes.org/user-guide/note-types/code), including - syntax highlighting -* Fast and easy [navigation between - notes](https://docs.triliumnotes.org/user-guide/concepts/navigation/note-navigation), - full text search and [note - hoisting](https://docs.triliumnotes.org/user-guide/concepts/navigation/note-hoisting) +* [सोर्स कोड वाले + नोट्स](https://docs.triliumnotes.org/user-guide/note-types/code) को एडिट करने + की सुविधा, जिसमें सिंटैक्स हाइलाइटिंग (syntax highlighting) भी शामिल है +* तेज़ और आसान [नोट्स के बीच + नेविगेशन](https://docs.triliumnotes.org/user-guide/concepts/navigation/note-navigation), + फुल टेक्स्ट सर्च और [नोट + होइस्टिंग](https://docs.triliumnotes.org/user-guide/concepts/navigation/note-hoisting) * Seamless [note versioning](https://docs.triliumnotes.org/user-guide/concepts/notes/note-revisions) * Note @@ -98,9 +98,8 @@ Our documentation is available in multiple formats: server](https://docs.triliumnotes.org/user-guide/setup/server/cloud-hosting) * [Sharing](https://docs.triliumnotes.org/user-guide/advanced-usage/sharing) (publishing) notes to public internet -* Strong [note - encryption](https://docs.triliumnotes.org/user-guide/concepts/notes/protected-notes) - with per-note granularity +* प्रति-नोट granularity के साथ मजबूत [नोट + एन्क्रिप्शन](https://docs.triliumnotes.org/user-guide/concepts/notes/protected-notes) * Sketching diagrams, based on [Excalidraw](https://excalidraw.com/) (note type "canvas") * [Relation diff --git a/docs/Release Notes/!!!meta.json b/docs/Release Notes/!!!meta.json index 77fb4118a..3c4265cdd 100644 --- a/docs/Release Notes/!!!meta.json +++ b/docs/Release Notes/!!!meta.json @@ -1,6 +1,6 @@ { "formatVersion": 2, - "appVersion": "0.101.1", + "appVersion": "0.101.3", "files": [ { "isClone": false, @@ -61,6 +61,58 @@ "attachments": [], "dirFileName": "Release Notes", "children": [ + { + "isClone": false, + "noteId": "IlBzLeN3MJhw", + "notePath": [ + "hD3V4hiu2VW4", + "IlBzLeN3MJhw" + ], + "title": "v0.101.3", + "notePosition": 10, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "template", + "value": "wyurrlcDl416", + "isInheritable": false, + "position": 60 + } + ], + "format": "markdown", + "dataFileName": "v0.101.3.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "vcBthaXcwAm6", + "notePath": [ + "hD3V4hiu2VW4", + "vcBthaXcwAm6" + ], + "title": "v0.101.2", + "notePosition": 20, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "template", + "value": "wyurrlcDl416", + "isInheritable": false, + "position": 60 + } + ], + "format": "markdown", + "dataFileName": "v0.101.2.md", + "attachments": [] + }, { "isClone": false, "noteId": "AgUcrU9nFXuW", @@ -69,7 +121,7 @@ "AgUcrU9nFXuW" ], "title": "v0.101.1", - "notePosition": 10, + "notePosition": 30, "prefix": null, "isExpanded": false, "type": "text", @@ -95,7 +147,7 @@ "uYwlZ594eyJu" ], "title": "v0.101.0", - "notePosition": 20, + "notePosition": 40, "prefix": null, "isExpanded": false, "type": "text", @@ -121,7 +173,7 @@ "iPGKEk7pwJXK" ], "title": "v0.100.0", - "notePosition": 30, + "notePosition": 50, "prefix": null, "isExpanded": false, "type": "text", @@ -147,7 +199,7 @@ "7HKMTjmopLcM" ], "title": "v0.99.5", - "notePosition": 40, + "notePosition": 60, "prefix": null, "isExpanded": false, "type": "text", @@ -173,7 +225,7 @@ "RMBaNYPsRpIr" ], "title": "v0.99.4", - "notePosition": 50, + "notePosition": 70, "prefix": null, "isExpanded": false, "type": "text", @@ -199,7 +251,7 @@ "yuroLztFfpu5" ], "title": "v0.99.3", - "notePosition": 60, + "notePosition": 80, "prefix": null, "isExpanded": false, "type": "text", @@ -225,7 +277,7 @@ "z207sehwMJ6C" ], "title": "v0.99.2", - "notePosition": 70, + "notePosition": 90, "prefix": null, "isExpanded": false, "type": "text", @@ -251,7 +303,7 @@ "WGQsXq2jNyTi" ], "title": "v0.99.1", - "notePosition": 80, + "notePosition": 100, "prefix": null, "isExpanded": false, "type": "text", @@ -277,7 +329,7 @@ "cyw2Yue9vXf3" ], "title": "v0.99.0", - "notePosition": 90, + "notePosition": 110, "prefix": null, "isExpanded": false, "type": "text", @@ -303,7 +355,7 @@ "QOJwjruOUr4k" ], "title": "v0.98.1", - "notePosition": 100, + "notePosition": 120, "prefix": null, "isExpanded": false, "type": "text", @@ -329,7 +381,7 @@ "PLUoryywi0BC" ], "title": "v0.98.0", - "notePosition": 110, + "notePosition": 130, "prefix": null, "isExpanded": false, "type": "text", @@ -355,7 +407,7 @@ "lvOuiWsLDv8F" ], "title": "v0.97.2", - "notePosition": 120, + "notePosition": 140, "prefix": null, "isExpanded": false, "type": "text", @@ -381,7 +433,7 @@ "OtFZ6Nd9vM3n" ], "title": "v0.97.1", - "notePosition": 130, + "notePosition": 150, "prefix": null, "isExpanded": false, "type": "text", @@ -407,7 +459,7 @@ "SJZ5PwfzHSQ1" ], "title": "v0.97.0", - "notePosition": 140, + "notePosition": 160, "prefix": null, "isExpanded": false, "type": "text", @@ -433,7 +485,7 @@ "mYXFde3LuNR7" ], "title": "v0.96.0", - "notePosition": 150, + "notePosition": 170, "prefix": null, "isExpanded": false, "type": "text", @@ -459,7 +511,7 @@ "jthwbL0FdaeU" ], "title": "v0.95.0", - "notePosition": 160, + "notePosition": 180, "prefix": null, "isExpanded": false, "type": "text", @@ -485,7 +537,7 @@ "7HGYsJbLuhnv" ], "title": "v0.94.1", - "notePosition": 170, + "notePosition": 190, "prefix": null, "isExpanded": false, "type": "text", @@ -511,7 +563,7 @@ "Neq53ujRGBqv" ], "title": "v0.94.0", - "notePosition": 180, + "notePosition": 200, "prefix": null, "isExpanded": false, "type": "text", @@ -537,7 +589,7 @@ "VN3xnce1vLkX" ], "title": "v0.93.0", - "notePosition": 190, + "notePosition": 210, "prefix": null, "isExpanded": false, "type": "text", @@ -555,7 +607,7 @@ "WRaBfQqPr6qo" ], "title": "v0.92.7", - "notePosition": 200, + "notePosition": 220, "prefix": null, "isExpanded": false, "type": "text", @@ -581,7 +633,7 @@ "a2rwfKNmUFU1" ], "title": "v0.92.6", - "notePosition": 210, + "notePosition": 230, "prefix": null, "isExpanded": false, "type": "text", @@ -599,7 +651,7 @@ "fEJ8qErr0BKL" ], "title": "v0.92.5-beta", - "notePosition": 220, + "notePosition": 240, "prefix": null, "isExpanded": false, "type": "text", @@ -617,7 +669,7 @@ "kkkZQQGSXjwy" ], "title": "v0.92.4", - "notePosition": 230, + "notePosition": 250, "prefix": null, "isExpanded": false, "type": "text", @@ -635,7 +687,7 @@ "vAroNixiezaH" ], "title": "v0.92.3-beta", - "notePosition": 240, + "notePosition": 260, "prefix": null, "isExpanded": false, "type": "text", @@ -653,7 +705,7 @@ "mHEq1wxAKNZd" ], "title": "v0.92.2-beta", - "notePosition": 250, + "notePosition": 270, "prefix": null, "isExpanded": false, "type": "text", @@ -671,7 +723,7 @@ "IykjoAmBpc61" ], "title": "v0.92.1-beta", - "notePosition": 260, + "notePosition": 280, "prefix": null, "isExpanded": false, "type": "text", @@ -689,7 +741,7 @@ "dq2AJ9vSBX4Y" ], "title": "v0.92.0-beta", - "notePosition": 270, + "notePosition": 290, "prefix": null, "isExpanded": false, "type": "text", @@ -707,7 +759,7 @@ "3a8aMe4jz4yM" ], "title": "v0.91.6", - "notePosition": 280, + "notePosition": 300, "prefix": null, "isExpanded": false, "type": "text", @@ -725,7 +777,7 @@ "8djQjkiDGESe" ], "title": "v0.91.5", - "notePosition": 290, + "notePosition": 310, "prefix": null, "isExpanded": false, "type": "text", @@ -743,7 +795,7 @@ "OylxVoVJqNmr" ], "title": "v0.91.4-beta", - "notePosition": 300, + "notePosition": 320, "prefix": null, "isExpanded": false, "type": "text", @@ -761,7 +813,7 @@ "tANGQDvnyhrj" ], "title": "v0.91.3-beta", - "notePosition": 310, + "notePosition": 330, "prefix": null, "isExpanded": false, "type": "text", @@ -779,7 +831,7 @@ "hMoBfwSoj1SC" ], "title": "v0.91.2-beta", - "notePosition": 320, + "notePosition": 340, "prefix": null, "isExpanded": false, "type": "text", @@ -797,7 +849,7 @@ "a2XMSKROCl9z" ], "title": "v0.91.1-beta", - "notePosition": 330, + "notePosition": 350, "prefix": null, "isExpanded": false, "type": "text", @@ -815,7 +867,7 @@ "yqXFvWbLkuMD" ], "title": "v0.90.12", - "notePosition": 340, + "notePosition": 360, "prefix": null, "isExpanded": false, "type": "text", @@ -833,7 +885,7 @@ "veS7pg311yJP" ], "title": "v0.90.11-beta", - "notePosition": 350, + "notePosition": 370, "prefix": null, "isExpanded": false, "type": "text", @@ -851,7 +903,7 @@ "sq5W9TQxRqMq" ], "title": "v0.90.10-beta", - "notePosition": 360, + "notePosition": 380, "prefix": null, "isExpanded": false, "type": "text", @@ -869,7 +921,7 @@ "yFEGVCUM9tPx" ], "title": "v0.90.9-beta", - "notePosition": 370, + "notePosition": 390, "prefix": null, "isExpanded": false, "type": "text", @@ -887,7 +939,7 @@ "o4wAGqOQuJtV" ], "title": "v0.90.8", - "notePosition": 380, + "notePosition": 400, "prefix": null, "isExpanded": false, "type": "text", @@ -920,7 +972,7 @@ "i4A5g9iOg9I0" ], "title": "v0.90.7-beta", - "notePosition": 390, + "notePosition": 410, "prefix": null, "isExpanded": false, "type": "text", @@ -938,7 +990,7 @@ "ThNf2GaKgXUs" ], "title": "v0.90.6-beta", - "notePosition": 400, + "notePosition": 420, "prefix": null, "isExpanded": false, "type": "text", @@ -956,7 +1008,7 @@ "G4PAi554kQUr" ], "title": "v0.90.5-beta", - "notePosition": 410, + "notePosition": 430, "prefix": null, "isExpanded": false, "type": "text", @@ -983,7 +1035,7 @@ "zATRobGRCmBn" ], "title": "v0.90.4", - "notePosition": 420, + "notePosition": 440, "prefix": null, "isExpanded": false, "type": "text", @@ -1001,7 +1053,7 @@ "sCDLf8IKn3Iz" ], "title": "v0.90.3", - "notePosition": 430, + "notePosition": 450, "prefix": null, "isExpanded": false, "type": "text", @@ -1019,7 +1071,7 @@ "VqqyBu4AuTjC" ], "title": "v0.90.2-beta", - "notePosition": 440, + "notePosition": 460, "prefix": null, "isExpanded": false, "type": "text", @@ -1037,7 +1089,7 @@ "RX3Nl7wInLsA" ], "title": "v0.90.1-beta", - "notePosition": 450, + "notePosition": 470, "prefix": null, "isExpanded": false, "type": "text", @@ -1055,7 +1107,7 @@ "GyueACukPWjk" ], "title": "v0.90.0-beta", - "notePosition": 460, + "notePosition": 480, "prefix": null, "isExpanded": false, "type": "text", @@ -1073,7 +1125,7 @@ "kzjHexDTTeVB" ], "title": "v0.48", - "notePosition": 470, + "notePosition": 490, "prefix": null, "isExpanded": false, "type": "text", @@ -1140,7 +1192,7 @@ "wyurrlcDl416" ], "title": "Release Template", - "notePosition": 480, + "notePosition": 500, "prefix": null, "isExpanded": false, "type": "text", diff --git a/docs/Release Notes/Release Notes/v0.101.2.md b/docs/Release Notes/Release Notes/v0.101.2.md new file mode 100644 index 000000000..6942b2e8e --- /dev/null +++ b/docs/Release Notes/Release Notes/v0.101.2.md @@ -0,0 +1,22 @@ +# v0.101.2 +> [!NOTE] +> If you are interested in an [official mobile application](https://oss.issuehunt.io/r/TriliumNext/Trilium/issues/7447)  ([#7447](https://github.com/TriliumNext/Trilium/issues/7447)) or [multi-user support](https://oss.issuehunt.io/r/TriliumNext/Trilium/issues/4956) ([#4956](https://github.com/TriliumNext/Trilium/issues/4956)), consider offering financial support via IssueHunt (see links). + +> [!IMPORTANT] +> If you enjoyed this release, consider showing a token of appreciation by: +> +> * Pressing the “Star” button on [GitHub](https://github.com/TriliumNext/Trilium) (top-right). +> * Considering a one-time or recurrent donation to the [lead developer](https://github.com/eliandoran) via [GitHub Sponsors](https://github.com/sponsors/eliandoran) or [PayPal](https://paypal.me/eliandoran). + +## 🐞 Bugfixes + +* [SQL Console: cannot copy table data](https://github.com/TriliumNext/Trilium/pull/8268) by @SiriusXT +* [Title is not selected when creating a note via the launcher](https://github.com/TriliumNext/Trilium/pull/8292) by @SiriusXT +* [Popup editor closing after inserting a note link](https://github.com/TriliumNext/Trilium/pull/8224) by @SiriusXT +* [New Mermaid diagrams do not save content](https://github.com/TriliumNext/Trilium/pull/8220) by @lzinga +* [Can't scroll mermaid diagram code](https://github.com/TriliumNext/Trilium/issues/8299) +* [Max content width is not respected when switching between note types in the same tab](https://github.com/TriliumNext/Trilium/issues/8065) +* [Crash When a Note Includes Itself](https://github.com/TriliumNext/Trilium/issues/8294) +* [Severe Performance Degradation and Crash Issues Due to Recursive Inclusion in Included Notes](https://github.com/TriliumNext/Trilium/issues/8017) +* [ is not a launcher even though it's in the launcher subtree](https://github.com/TriliumNext/Trilium/issues/8218) +* [Archived subnotes of direct children appear in grid view without #includeArchived](https://github.com/TriliumNext/Trilium/issues/8184) \ No newline at end of file diff --git a/docs/Release Notes/Release Notes/v0.101.3.md b/docs/Release Notes/Release Notes/v0.101.3.md new file mode 100644 index 000000000..243034045 --- /dev/null +++ b/docs/Release Notes/Release Notes/v0.101.3.md @@ -0,0 +1,24 @@ +# v0.101.3 +> [!NOTE] +> If you are interested in an [official mobile application](https://oss.issuehunt.io/r/TriliumNext/Trilium/issues/7447)  ([#7447](https://github.com/TriliumNext/Trilium/issues/7447)) or [multi-user support](https://oss.issuehunt.io/r/TriliumNext/Trilium/issues/4956) ([#4956](https://github.com/TriliumNext/Trilium/issues/4956)), consider offering financial support via IssueHunt (see links). + +> [!IMPORTANT] +> If you enjoyed this release, consider showing a token of appreciation by: +> +> * Pressing the “Star” button on [GitHub](https://github.com/TriliumNext/Trilium) (top-right). +> * Considering a one-time or recurrent donation to the [lead developer](https://github.com/eliandoran) via [GitHub Sponsors](https://github.com/sponsors/eliandoran) or [PayPal](https://paypal.me/eliandoran). + +This is a re-release of v0.101.2, which had a cache invalidation issue. + +## 🐞 Bugfixes + +* [SQL Console: cannot copy table data](https://github.com/TriliumNext/Trilium/pull/8268) by @SiriusXT +* [Title is not selected when creating a note via the launcher](https://github.com/TriliumNext/Trilium/pull/8292) by @SiriusXT +* [Popup editor closing after inserting a note link](https://github.com/TriliumNext/Trilium/pull/8224) by @SiriusXT +* [New Mermaid diagrams do not save content](https://github.com/TriliumNext/Trilium/pull/8220) by @lzinga +* [Can't scroll mermaid diagram code](https://github.com/TriliumNext/Trilium/issues/8299) +* [Max content width is not respected when switching between note types in the same tab](https://github.com/TriliumNext/Trilium/issues/8065) +* [Crash When a Note Includes Itself](https://github.com/TriliumNext/Trilium/issues/8294) +* [Severe Performance Degradation and Crash Issues Due to Recursive Inclusion in Included Notes](https://github.com/TriliumNext/Trilium/issues/8017) +* [is not a launcher even though it's in the launcher subtree](https://github.com/TriliumNext/Trilium/issues/8218) +* [Archived subnotes of direct children appear in grid view without #includeArchived](https://github.com/TriliumNext/Trilium/issues/8184) \ No newline at end of file diff --git a/docs/User Guide/!!!meta.json b/docs/User Guide/!!!meta.json index 50b9abb02..da318029b 100644 --- a/docs/User Guide/!!!meta.json +++ b/docs/User Guide/!!!meta.json @@ -1,6 +1,6 @@ { "formatVersion": 2, - "appVersion": "0.101.1", + "appVersion": "0.101.3", "files": [ { "isClone": false, @@ -2426,6 +2426,122 @@ "format": "markdown", "dataFileName": "Keyboard shortcuts.md", "attachments": [] + }, + { + "isClone": false, + "noteId": "wyaGBBQrl4i3", + "notePath": [ + "pOsGYCXsbNQG", + "gh7bpGYxajRS", + "Vc8PjrjAGuOp", + "oPVyFC7WL2Lp", + "wyaGBBQrl4i3" + ], + "title": "Hiding the subtree", + "notePosition": 40, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "hiding-subtree", + "isInheritable": false, + "position": 30 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-hide", + "isInheritable": false, + "position": 40 + }, + { + "type": "relation", + "name": "internalLink", + "value": "GTwFsgaA0lCt", + "isInheritable": false, + "position": 50 + }, + { + "type": "relation", + "name": "internalLink", + "value": "CtBQqbwXDx1w", + "isInheritable": false, + "position": 60 + }, + { + "type": "relation", + "name": "internalLink", + "value": "2FvYrpmOXm29", + "isInheritable": false, + "position": 70 + }, + { + "type": "relation", + "name": "internalLink", + "value": "IjZS7iK5EXtb", + "isInheritable": false, + "position": 80 + }, + { + "type": "relation", + "name": "internalLink", + "value": "oPVyFC7WL2Lp", + "isInheritable": false, + "position": 90 + }, + { + "type": "relation", + "name": "internalLink", + "value": "zP3PMqaG71Ct", + "isInheritable": false, + "position": 100 + }, + { + "type": "relation", + "name": "internalLink", + "value": "hrZ1D00cLbal", + "isInheritable": false, + "position": 110 + }, + { + "type": "relation", + "name": "internalLink", + "value": "eIg8jdvaoNNd", + "isInheritable": false, + "position": 120 + }, + { + "type": "relation", + "name": "internalLink", + "value": "TBwsyfadTA18", + "isInheritable": false, + "position": 130 + } + ], + "format": "markdown", + "dataFileName": "Hiding the subtree.md", + "attachments": [ + { + "attachmentId": "d9Sq9avKDptU", + "title": "image.png", + "role": "image", + "mime": "image/png", + "position": 10, + "dataFileName": "Hiding the subtree_image.png" + }, + { + "attachmentId": "VmRtx3vS97v1", + "title": "image.png", + "role": "image", + "mime": "image/png", + "position": 10, + "dataFileName": "1_Hiding the subtree_image.png" + } + ] } ] }, diff --git a/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/1_Hiding the subtree_image.png b/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/1_Hiding the subtree_image.png new file mode 100644 index 000000000..44f0bbe51 Binary files /dev/null and b/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/1_Hiding the subtree_image.png differ diff --git a/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree.md b/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree.md new file mode 100644 index 000000000..9c9b75455 --- /dev/null +++ b/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree.md @@ -0,0 +1,55 @@ +# Hiding the subtree +
    An example of a collection with a relatively large number of children that are hidden from the tree.
    + +The tree works well when the notes are structured in a hierarchy so that the number of items stays small. When a note has a large number of notes (in the order of thousands or tens of thousands), two problems arise: + +* Navigating between notes becomes cumbersome and the tree itself gets cluttered with a large amount of notes. +* The large amount of notes can slow down the application considerably. + +Since v0.102.0, Trilium allows the tree to hide the child notes of particular notes. This works for both Collections and normal notes. + +## Interaction + +When the subtree of a note is hidden, there are a few subtle changes: + +* To indicate that the subtree is hidden, the note will not have an expand button and it will display the number of children to the right. +* It's not possible to add a new note directly from the tree. + * For Collections, it's best to use the built-in mechanism to create notes (for example by creating a new point on a geo-map, or by adding a new row in a table). + * For normal notes, it's still possible to create children via other means such as using the Internal (reference) links system. +* Notes can be dragged from outside the note, case in which they will be cloned into it. + * Instead of switching to the child notes that were copied, the parent note is highlighted instead. + * A notification will indicate this behavior. +* Similarly, features such as cut/copy and then paste into the note will also work. + +## Spotlighting + +
    + +Even if the subtree of a note is hidden, if a child note manages to become active, it will still appear inside the tree in a special state called _spotlighted_. + +During this state, the note remains under its normal hierarchy, so that its easy to tell its location. In addition, this means that: + +* The note position is clearly visible when using the Search. +* The note can still be operated on from the tree, such as adding a Branch prefix or moving it outside the collection. + +The note appears in italics to indicate its temporary display. When switching to another note, the spotlighted note will disappear. + +> [!NOTE] +> Only one note can be highlighted at the time. When working with multiple notes such as dragging them into the collection, no note will be spotlighted. This is intentional to avoid displaying a partial state of the subtree. + +## Working with collections + +By default, some of the Collections will automatically hide their child notes, for example the Kanban Board or the Table. + +The reasoning behind this is that collections are generally opaque to the rest of the notes and they can generate a large amount of sub-notes since they intentionally lack structure (in order to allow easy swapping between views). + +Some types of collections have the child notes intentionally shown, for example the legacy ones (Grid and List), but also the Presentation which requires the tree structure in order to organize and edit the slides. + +To toggle this behavior: + +* In the New Layout, press the Options button underneath the title and uncheck _Hide child notes in tree_. +* Right click the collection note in the Note Tree and select _Advanced_ → _Show subtree_. + +## Working with normal notes + +It's possible to hide the subtree for normal notes as well, not just collections. To do so, right click the note in the Note Tree and select _Advanced_ → _Hide subtree._ \ No newline at end of file diff --git a/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree_image.png b/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree_image.png new file mode 100644 index 000000000..7b75834e9 Binary files /dev/null and b/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree_image.png differ diff --git a/docs/User Guide/User Guide/FAQ.md b/docs/User Guide/User Guide/FAQ.md index e97cbecc6..48a79cf21 100644 --- a/docs/User Guide/User Guide/FAQ.md +++ b/docs/User Guide/User Guide/FAQ.md @@ -44,7 +44,7 @@ No. These general purpose sync apps are not suitable to sync database files which are open and being worked on by another application. The result is that they will corrupt the database file, resulting in data loss and this message in the Trilium logs: -```plain +``` SqliteError: database disk image is malformed ``` diff --git a/package.json b/package.json index 711ebbee5..cda34aeb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@triliumnext/source", - "version": "0.101.1", + "version": "0.101.3", "description": "Build your personal knowledge base with Trilium Notes", "directories": { "doc": "docs" @@ -90,7 +90,7 @@ "url": "https://github.com/TriliumNext/Trilium/issues" }, "homepage": "https://triliumnotes.org", - "packageManager": "pnpm@10.27.0", + "packageManager": "pnpm@10.28.0", "pnpm": { "patchedDependencies": { "@ckeditor/ckeditor5-mention": "patches/@ckeditor__ckeditor5-mention.patch", diff --git a/packages/commons/package.json b/packages/commons/package.json index bc854c279..0b30be811 100644 --- a/packages/commons/package.json +++ b/packages/commons/package.json @@ -1,6 +1,6 @@ { "name": "@triliumnext/commons", - "version": "0.101.1", + "version": "0.101.3", "description": "Shared library between the clients (e.g. browser, Electron) and the server, mostly for type definitions and utility methods.", "private": true, "type": "module", diff --git a/packages/commons/src/lib/attribute_names.ts b/packages/commons/src/lib/attribute_names.ts index afb45fcb3..b524b409f 100644 --- a/packages/commons/src/lib/attribute_names.ts +++ b/packages/commons/src/lib/attribute_names.ts @@ -22,6 +22,9 @@ type Labels = { pageUrl: string; dateNote: string; + // Tree specific + subtreeHidden: boolean; + // Search searchString: string; ancestorDepth: string; diff --git a/packages/commons/src/lib/shared_constants.ts b/packages/commons/src/lib/shared_constants.ts index bf13c92d3..c88044162 100644 --- a/packages/commons/src/lib/shared_constants.ts +++ b/packages/commons/src/lib/shared_constants.ts @@ -18,5 +18,5 @@ export const ALLOWED_PROTOCOLS = [ 'gopher', 'imap', 'irc', 'irc6', 'jabber', 'jar', 'lastfm', 'ldap', 'ldaps', 'magnet', 'message', 'mumble', 'nfs', 'onenote', 'pop', 'rmi', 's3', 'sftp', 'skype', 'sms', 'spotify', 'steam', 'svn', 'udp', 'view-source', 'vlc', 'vnc', 'ws', 'wss', 'xmpp', 'jdbc', 'slack', 'tel', 'smb', 'zotero', 'geo', - 'mid', 'obsidian' + 'logseq', 'mid', 'obsidian' ]; diff --git a/scripts/check-version-consistency.ts b/scripts/check-version-consistency.ts new file mode 100644 index 000000000..235167b2d --- /dev/null +++ b/scripts/check-version-consistency.ts @@ -0,0 +1,33 @@ +import { readFileSync } from "fs"; +import { join } from "path"; + +const projectRoot = join(__dirname, '..'); +const filesToCheck = [ + 'package.json', + 'apps/server/package.json', + 'apps/client/package.json', + 'apps/desktop/package.json', + 'packages/commons/package.json', +] + +function main() { + const expectedVersion = process.argv[2]; + if (!expectedVersion) { + console.error('Expected version argument is missing.'); + process.exit(1); + } + + for (const fileToCheck of filesToCheck) { + const packageJsonPath = join(projectRoot, fileToCheck); + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')); + const version = packageJson.version; + if (version !== expectedVersion) { + console.error(`Version mismatch in ${fileToCheck}: expected ${expectedVersion}, found ${version}`); + process.exit(1); + } + } + + console.log('All versions are consistent:', expectedVersion); +} + +main();