diff --git a/_regroup/package.json b/_regroup/package.json index fd13c78f1..ce0e70d45 100644 --- a/_regroup/package.json +++ b/_regroup/package.json @@ -41,7 +41,7 @@ "@types/node": "24.10.0", "@types/yargs": "17.0.34", "@vitest/coverage-v8": "3.2.4", - "eslint": "9.39.0", + "eslint": "9.39.1", "eslint-plugin-simple-import-sort": "12.1.1", "esm": "3.2.25", "jsdoc": "4.0.5", diff --git a/apps/build-docs/package.json b/apps/build-docs/package.json index f22baec81..00196de82 100644 --- a/apps/build-docs/package.json +++ b/apps/build-docs/package.json @@ -11,7 +11,7 @@ "license": "AGPL-3.0-only", "packageManager": "pnpm@10.20.0", "devDependencies": { - "@redocly/cli": "2.10.0", + "@redocly/cli": "2.11.0", "archiver": "7.0.1", "fs-extra": "11.3.2", "react": "19.2.0", diff --git a/apps/build-docs/src/main.ts b/apps/build-docs/src/main.ts index 19d533420..d94ada167 100644 --- a/apps/build-docs/src/main.ts +++ b/apps/build-docs/src/main.ts @@ -22,8 +22,9 @@ async function main() { buildSwagger(context); buildScriptApi(context); - // Copy index file. + // Copy index and 404 files. cpSync(join(__dirname, "index.html"), join(context.baseDir, "index.html")); + cpSync(join(context.baseDir, "user-guide/404.html"), join(context.baseDir, "404.html")); } main(); diff --git a/apps/client/package.json b/apps/client/package.json index c080281ec..5ecf18cac 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -15,7 +15,7 @@ "circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular" }, "dependencies": { - "@eslint/js": "9.39.0", + "@eslint/js": "9.39.1", "@excalidraw/excalidraw": "0.18.0", "@fullcalendar/core": "6.1.19", "@fullcalendar/daygrid": "6.1.19", @@ -59,7 +59,7 @@ "normalize.css": "8.0.1", "panzoom": "9.4.3", "preact": "10.27.2", - "react-i18next": "16.2.3", + "react-i18next": "16.2.4", "reveal.js": "5.2.1", "svg-pan-zoom": "3.6.2", "tabulator-tables": "6.3.1", diff --git a/apps/client/src/menus/tree_context_menu.ts b/apps/client/src/menus/tree_context_menu.ts index 6504b49eb..7384573d8 100644 --- a/apps/client/src/menus/tree_context_menu.ts +++ b/apps/client/src/menus/tree_context_menu.ts @@ -137,7 +137,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener { expect(matchesShortcut(event, "Shift+F1")).toBeTruthy(); // Special keys - for (const keyCode of [ "Delete", "Enter" ]) { + for (const keyCode of [ "Delete", "Enter", "NumpadEnter" ]) { event = createKeyboardEvent({ key: keyCode, code: keyCode }); expect(matchesShortcut(event, keyCode), `Key ${keyCode}`).toBeTruthy(); } diff --git a/apps/client/src/services/shortcuts.ts b/apps/client/src/services/shortcuts.ts index 94dd8893c..7d6a1e956 100644 --- a/apps/client/src/services/shortcuts.ts +++ b/apps/client/src/services/shortcuts.ts @@ -46,6 +46,7 @@ for (let i = 1; i <= 19; i++) { const KEYCODES_WITH_NO_MODIFIER = new Set([ "Delete", "Enter", + "NumpadEnter", ...functionKeyCodes ]); diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 1868619d4..ff732a04b 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -36,10 +36,13 @@ }, "branch_prefix": { "edit_branch_prefix": "Edit branch prefix", + "edit_branch_prefix_multiple": "Edit branch prefix for {{count}} branches", "help_on_tree_prefix": "Help on Tree prefix", "prefix": "Prefix: ", "save": "Save", - "branch_prefix_saved": "Branch prefix has been saved." + "branch_prefix_saved": "Branch prefix has been saved.", + "branch_prefix_saved_multiple": "Branch prefix has been saved for {{count}} branches.", + "affected_branches": "Affected branches ({{count}}):" }, "bulk_actions": { "bulk_actions": "Bulk actions", diff --git a/apps/client/src/translations/it/translation.json b/apps/client/src/translations/it/translation.json index d9b760dd8..a06fe08f5 100644 --- a/apps/client/src/translations/it/translation.json +++ b/apps/client/src/translations/it/translation.json @@ -109,7 +109,8 @@ "export_type_single": "Solo questa nota, senza le sottostanti", "format_opml": "OPML - formato per scambio informazioni outline. Formattazione, immagini e files non sono inclusi.", "opml_version_1": "OPML v.1.0 - solo testo semplice", - "opml_version_2": "OPML v2.0 - supporta anche HTML" + "opml_version_2": "OPML v2.0 - supporta anche HTML", + "share-format": "HTML per la pubblicazione sul web - utilizza lo stesso tema utilizzato per le note condivise, ma può essere pubblicato come sito web statico." }, "password_not_set": { "body1": "Le note protette sono crittografate utilizzando una password utente, ma la password non è stata ancora impostata.", diff --git a/apps/client/src/widgets/dialogs/branch_prefix.css b/apps/client/src/widgets/dialogs/branch_prefix.css new file mode 100644 index 000000000..3470f1018 --- /dev/null +++ b/apps/client/src/widgets/dialogs/branch_prefix.css @@ -0,0 +1,13 @@ +.branch-prefix-dialog .branch-prefix-notes-list { + margin-top: 10px; +} + +.branch-prefix-dialog .branch-prefix-notes-list ul { + max-height: 200px; + overflow: auto; + margin-top: 5px; +} + +.branch-prefix-dialog .branch-prefix-current { + opacity: 0.6; +} diff --git a/apps/client/src/widgets/dialogs/branch_prefix.tsx b/apps/client/src/widgets/dialogs/branch_prefix.tsx index 46888f0ab..e715c894f 100644 --- a/apps/client/src/widgets/dialogs/branch_prefix.tsx +++ b/apps/client/src/widgets/dialogs/branch_prefix.tsx @@ -10,53 +10,86 @@ import Button from "../react/Button.jsx"; import FormGroup from "../react/FormGroup.js"; import { useTriliumEvent } from "../react/hooks.jsx"; import FBranch from "../../entities/fbranch.js"; +import type { ContextMenuCommandData } from "../../components/app_context.js"; +import "./branch_prefix.css"; + +// Virtual branches (e.g., from search results) start with this prefix +const VIRTUAL_BRANCH_PREFIX = "virt-"; export default function BranchPrefixDialog() { const [ shown, setShown ] = useState(false); - const [ branch, setBranch ] = useState(); + const [ branches, setBranches ] = useState([]); const [ prefix, setPrefix ] = useState(""); const branchInput = useRef(null); - useTriliumEvent("editBranchPrefix", async () => { - const notePath = appContext.tabManager.getActiveContextNotePath(); - if (!notePath) { + useTriliumEvent("editBranchPrefix", async (data?: ContextMenuCommandData) => { + let branchIds: string[] = []; + + if (data?.selectedOrActiveBranchIds && data.selectedOrActiveBranchIds.length > 0) { + // Multi-select mode from tree context menu + branchIds = data.selectedOrActiveBranchIds.filter((branchId) => !branchId.startsWith(VIRTUAL_BRANCH_PREFIX)); + } else { + // Single branch mode from keyboard shortcut or when no selection + const notePath = appContext.tabManager.getActiveContextNotePath(); + if (!notePath) { + return; + } + + const { noteId, parentNoteId } = tree.getNoteIdAndParentIdFromUrl(notePath); + + if (!noteId || !parentNoteId) { + return; + } + + const branchId = await froca.getBranchId(parentNoteId, noteId); + if (!branchId) { + return; + } + const parentNote = await froca.getNote(parentNoteId); + if (!parentNote || parentNote.type === "search") { + return; + } + + branchIds = [branchId]; + } + + if (branchIds.length === 0) { return; } - const { noteId, parentNoteId } = tree.getNoteIdAndParentIdFromUrl(notePath); + const newBranches = branchIds + .map(id => froca.getBranch(id)) + .filter((branch): branch is FBranch => branch !== null); - if (!noteId || !parentNoteId) { + if (newBranches.length === 0) { return; } - const newBranchId = await froca.getBranchId(parentNoteId, noteId); - if (!newBranchId) { - return; - } - const parentNote = await froca.getNote(parentNoteId); - if (!parentNote || parentNote.type === "search") { - return; - } - - const newBranch = froca.getBranch(newBranchId); - setBranch(newBranch); - setPrefix(newBranch?.prefix ?? ""); + setBranches(newBranches); + // Use the prefix of the first branch as the initial value + setPrefix(newBranches[0]?.prefix ?? ""); setShown(true); }); async function onSubmit() { - if (!branch) { + if (branches.length === 0) { return; } - savePrefix(branch.branchId, prefix); + if (branches.length === 1) { + await savePrefix(branches[0].branchId, prefix); + } else { + await savePrefixBatch(branches.map(b => b.branchId), prefix); + } setShown(false); } + const isSingleBranch = branches.length === 1; + return ( branchInput.current?.focus()} onHidden={() => setShown(false)} @@ -69,9 +102,27 @@ export default function BranchPrefixDialog() {
setPrefix((e.target as HTMLInputElement).value)} /> -
- {branch && branch.getNoteFromCache().title}
+ {isSingleBranch && branches[0] && ( +
- {branches[0].getNoteFromCache().title}
+ )}
+ {!isSingleBranch && ( +
+ {t("branch_prefix.affected_branches", { count: branches.length })} +
    + {branches.map((branch) => { + const note = branch.getNoteFromCache(); + return ( +
  • + {branch.prefix && {branch.prefix} - } + {note.title} +
  • + ); + })} +
+
+ )}
); } @@ -80,3 +131,8 @@ async function savePrefix(branchId: string, prefix: string) { await server.put(`branches/${branchId}/set-prefix`, { prefix: prefix }); toast.showMessage(t("branch_prefix.branch_prefix_saved")); } + +async function savePrefixBatch(branchIds: string[], prefix: string) { + await server.put("branches/set-prefix-batch", { branchIds, prefix }); + toast.showMessage(t("branch_prefix.branch_prefix_saved_multiple", { count: branchIds.length })); +} diff --git a/apps/client/src/widgets/note_tree.ts b/apps/client/src/widgets/note_tree.ts index f1c2ca736..cb2120687 100644 --- a/apps/client/src/widgets/note_tree.ts +++ b/apps/client/src/widgets/note_tree.ts @@ -1591,6 +1591,20 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { this.clearSelectedNodes(); } + async editBranchPrefixCommand({ node }: CommandListenerData<"editBranchPrefix">) { + const branchIds = this.getSelectedOrActiveBranchIds(node).filter((branchId) => !branchId.startsWith("virt-")); + + if (!branchIds.length) { + return; + } + + // Trigger the event with the selected branch IDs + appContext.triggerEvent("editBranchPrefix", { + selectedOrActiveBranchIds: branchIds, + node: node + }); + } + canBeMovedUpOrDown(node: Fancytree.FancytreeNode) { if (node.data.noteId === "root") { return false; diff --git a/apps/client/src/widgets/ribbon/EditedNotesTab.tsx b/apps/client/src/widgets/ribbon/EditedNotesTab.tsx index 5bab1c816..4bdae4126 100644 --- a/apps/client/src/widgets/ribbon/EditedNotesTab.tsx +++ b/apps/client/src/widgets/ribbon/EditedNotesTab.tsx @@ -13,8 +13,8 @@ export default function EditedNotesTab({ note }: TabContext) { useEffect(() => { if (!note) return; server.get(`edited-notes/${note.getLabelValue("dateNote")}`).then(async editedNotes => { - editedNotes = editedNotes.filter((n) => n.noteId !== note.noteId); - const noteIds = editedNotes.flatMap((n) => n.noteId); + editedNotes = editedNotes.filter((n) => n.noteId !== note.noteId); + const noteIds = editedNotes.flatMap((n) => n.noteId); await froca.getNotes(noteIds, true); // preload all at once setEditedNotes(editedNotes); }); @@ -41,11 +41,11 @@ export default function EditedNotesTab({ note }: TabContext) { )} ) - }))} + }), " ")} ) : (
{t("edited_notes.no_edited_notes_found")}
)} - ) + ) } diff --git a/apps/client/src/widgets/type_widgets/options/text_notes.tsx b/apps/client/src/widgets/type_widgets/options/text_notes.tsx index 4e2475922..0dd102145 100644 --- a/apps/client/src/widgets/type_widgets/options/text_notes.tsx +++ b/apps/client/src/widgets/type_widgets/options/text_notes.tsx @@ -72,8 +72,8 @@ function EditorFeatures() { return ( - - + + ); } diff --git a/apps/edit-docs/demo/!!!meta.json b/apps/edit-docs/demo/!!!meta.json index ce5046fb1..44b61171d 100644 --- a/apps/edit-docs/demo/!!!meta.json +++ b/apps/edit-docs/demo/!!!meta.json @@ -1,6 +1,6 @@ { "formatVersion": 2, - "appVersion": "0.99.2", + "appVersion": "0.99.3", "files": [ { "isClone": false, @@ -2700,6 +2700,7 @@ } ], "format": "html", + "dataFileName": "Note Types.html", "attachments": [], "dirFileName": "Note Types", "children": [ diff --git a/apps/edit-docs/demo/navigation.html b/apps/edit-docs/demo/navigation.html index 1d4d5d57b..4d1371ac2 100644 --- a/apps/edit-docs/demo/navigation.html +++ b/apps/edit-docs/demo/navigation.html @@ -270,7 +270,7 @@ -
  • Note Types +
  • Note Types
    • Canvas
    • diff --git a/apps/edit-docs/demo/root/Miscellaneous/Day Note Template.html b/apps/edit-docs/demo/root/Miscellaneous/Day Note Template.html index 8f2333bf0..a33b14490 100644 --- a/apps/edit-docs/demo/root/Miscellaneous/Day Note Template.html +++ b/apps/edit-docs/demo/root/Miscellaneous/Day Note Template.html @@ -14,6 +14,7 @@

      ☑️ Tasks

      +
      • […]
      diff --git a/apps/edit-docs/demo/root/Trilium Demo.html b/apps/edit-docs/demo/root/Trilium Demo.html index 206054b92..b5b6672d6 100644 --- a/apps/edit-docs/demo/root/Trilium Demo.html +++ b/apps/edit-docs/demo/root/Trilium Demo.html @@ -14,11 +14,10 @@
      - +

      Welcome to Trilium Notes! -

      This is a "demo" document packaged with Trilium to showcase some of its features and also give you some ideas on how you might structure your notes. @@ -26,22 +25,17 @@ you wish.

      If you need any help, visit triliumnotes.org or our GitHub repository -

      Cleanup

      -

      Once you're finished with experimenting and want to cleanup these pages, you can simply delete them all.

      Formatting

      -

      Trilium supports classic formatting like italic, bold, bold and italic. You can add links pointing to external pages or  Formatting examples.

      Lists

      -

      Ordered: -

      1. First Item
      2. @@ -56,7 +50,6 @@

      Unordered: -

      • Item
      • @@ -67,7 +60,6 @@

      Block quotes

      -

      Whereof one cannot speak, thereof one must be silent”

      – Ludwig Wittgenstein

      @@ -75,9 +67,9 @@

      See also other examples like tables, checkbox lists, highlighting, + href="Trilium%20Demo/Formatting%20examples/Checkbox%20lists.html">checkbox lists, highlighting, code blocksand code blocksand math examples.

      + href="Trilium%20Demo/Formatting%20examples/Math.html">math examples.

      diff --git a/apps/edit-docs/demo/root/Trilium Demo/Formatting examples/Code blocks.html b/apps/edit-docs/demo/root/Trilium Demo/Formatting examples/Code blocks.html index 6827fa8af..214ef212e 100644 --- a/apps/edit-docs/demo/root/Trilium Demo/Formatting examples/Code blocks.html +++ b/apps/edit-docs/demo/root/Trilium Demo/Formatting examples/Code blocks.html @@ -21,8 +21,12 @@ language, should that fail it is possible to manually adjust it. The color scheme for the syntax highlighting is adjustable in settings. 

      function helloWorld() {
       
      +
      +
       	alert("Hello world");
       
      +
      +
       }

      For larger pieces of code it is better to use a code note, which uses a fully-fledged code editor (CodeMirror). For an example of a code note, diff --git a/apps/edit-docs/demo/root/Trilium Demo/Note Types.html b/apps/edit-docs/demo/root/Trilium Demo/Note Types.html new file mode 100644 index 000000000..614d566bc --- /dev/null +++ b/apps/edit-docs/demo/root/Trilium Demo/Note Types.html @@ -0,0 +1,21 @@ + + + + + + + + Note Types + + + +

      +

      Note Types

      + +
      +

      T

      +
      +
      + + + \ No newline at end of file diff --git a/apps/edit-docs/demo/root/Trilium Demo/Scripting examples/Task manager.html b/apps/edit-docs/demo/root/Trilium Demo/Scripting examples/Task manager.html index 1b4822074..266520b60 100644 --- a/apps/edit-docs/demo/root/Trilium Demo/Scripting examples/Task manager.html +++ b/apps/edit-docs/demo/root/Trilium Demo/Scripting examples/Task manager.html @@ -13,9 +13,8 @@

      Task manager

      -

      This is a simple TODO/Task manager. You can see some description and explanation - here: https://github.com/zadam/trilium/wiki/Task-manager -

      +

      This is a simple TODO/Task manager. See the Trilium documentation for + information on how it works.

      Please note that this is meant as scripting example only and feature/bug support is very limited.

      diff --git a/apps/edit-docs/demo/root/Trilium Demo/Tech/Linux/Bash scripting/While loop.html b/apps/edit-docs/demo/root/Trilium Demo/Tech/Linux/Bash scripting/While loop.html index 752bedbd2..39ca1e373 100644 --- a/apps/edit-docs/demo/root/Trilium Demo/Tech/Linux/Bash scripting/While loop.html +++ b/apps/edit-docs/demo/root/Trilium Demo/Tech/Linux/Bash scripting/While loop.html @@ -16,18 +16,32 @@

      Documentation: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_02.html

      #!/bin/bash
       
      +
      +
       # This script opens 4 terminal windows.
       
      +
      +
       i="0"
       
      +
      +
       while [ $i -lt 4 ]
       
      +
      +
       do
       
      +
      +
           xterm &
       
      +
      +
           i=$[$i+1]
       
      +
      +
       done
      diff --git a/apps/edit-docs/package.json b/apps/edit-docs/package.json index cc664e81d..958a54f3d 100644 --- a/apps/edit-docs/package.json +++ b/apps/edit-docs/package.json @@ -17,6 +17,6 @@ }, "scripts": { "edit-docs": "cross-env TRILIUM_PORT=37741 TRILIUM_DATA_DIR=data TRILIUM_INTEGRATION_TEST=memory-no-store DOCS_ROOT=../../../docs USER_GUIDE_ROOT=\"../../server/src/assets/doc_notes/en/User Guide\" tsx ../../scripts/electron-start.mts src/edit-docs.ts", - "edit-demo": "cross-env TRILIUM_PORT=37741 TRILIUM_DATA_DIR=data TRILIUM_INTEGRATION_TEST=memory-no-store DOCS_ROOT=../../../docs USER_GUIDE_ROOT=\"../../server/src/assets/doc_notes/en/User Guide\" tsx ../../scripts/electron-start.mts src/edit-demo.ts" + "edit-demo": "cross-env TRILIUM_PORT=37744 TRILIUM_DATA_DIR=data TRILIUM_INTEGRATION_TEST=memory-no-store DOCS_ROOT=../../../docs USER_GUIDE_ROOT=\"../../server/src/assets/doc_notes/en/User Guide\" tsx ../../scripts/electron-start.mts src/edit-demo.ts" } } \ No newline at end of file diff --git a/apps/server/package.json b/apps/server/package.json index d6d634be2..602651c97 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -67,7 +67,7 @@ "@types/xml2js": "0.4.14", "archiver": "7.0.1", "async-mutex": "0.5.0", - "axios": "1.13.1", + "axios": "1.13.2", "bindings": "1.5.0", "bootstrap": "5.3.8", "chardet": "2.1.1", @@ -110,12 +110,12 @@ "multer": "2.0.2", "normalize-strings": "1.1.1", "ollama": "0.6.2", - "openai": "6.7.0", + "openai": "6.8.0", "rand-token": "1.0.1", "safe-compare": "1.1.4", "sanitize-filename": "1.6.3", "sanitize-html": "2.17.0", - "sax": "1.4.1", + "sax": "1.4.3", "serve-favicon": "2.5.1", "stream-throttle": "0.1.3", "strip-bom": "5.0.0", diff --git a/apps/server/src/assets/db/demo.zip b/apps/server/src/assets/db/demo.zip index ebf3f8a7c..c4cbc6058 100644 Binary files a/apps/server/src/assets/db/demo.zip and b/apps/server/src/assets/db/demo.zip 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 54c139517..570196694 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_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_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_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_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_ZjLYv08Rp3qC","title":"Quick edit","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Quick edit"},{"name":"iconClass","value":"bx bx-file","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_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.clone"},{"name":"iconClass","value":"bx bx-file","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_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_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"}]}]},{"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_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 HTML for web publishing","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Exporting HTML for web publish"},{"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_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-info-circle","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/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/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/Examples/Using promoted attributes to c"},{"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/Events"},{"name":"iconClass","value":"bx bx-rss","type":"label"}]},{"id":"_help_MgibgPcfeuGz","title":"Custom Widgets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Custom Widgets"},{"name":"iconClass","value":"bx bxs-widget","type":"label"}],"children":[{"id":"_help_YNxAqkI5Kg1M","title":"Word count widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Custom Widgets/Word count widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_SynTBQiBsdYJ","title":"Widget Basics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Custom Widgets/Widget Basics"},{"name":"iconClass","value":"bx bx-file","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_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_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_ZjLYv08Rp3qC","title":"Quick edit","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Quick edit"},{"name":"iconClass","value":"bx bx-file","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_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.clone"},{"name":"iconClass","value":"bx bx-file","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_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_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"}]}]},{"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_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 HTML for web publishing","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Exporting HTML for web publish"},{"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_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_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_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_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_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_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_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_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/AI.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/AI.html index e94560b68..11ad7e821 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/AI.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/AI.html @@ -19,8 +19,7 @@ class="image image_resized" style="width:74.04%;"> - -

      Embeddings

      +

      Embeddings

      Embeddings are important as it allows us to have an compact AI “summary” (it's not human readable text) of each of your Notes, that we can then perform mathematical functions on (such as cosine similarity) @@ -36,7 +35,7 @@ class="image image_resized" style="width:74.04%;">

      To see what embedding models Ollama has available, you can check out this searchon their website, and then pull whichever one - you want to try out. As of 4/15/25, my personal favorite is mxbai-embed-large.

      + you want to try out. A popular choice is mxbai-embed-large.

      First, we'll need to select the Ollama provider from the tabs of providers, then we will enter in the Base URL for our Ollama. Since our Ollama is running on our local machine, our Base URL is http://localhost:11434. @@ -80,59 +79,59 @@ class="image image_resized" style="width:74.04%;">

      These are the tools that currently exist, and will certainly be updated to be more effectively (and even more to be added!):

        -
      • search_notes +
      • search_notes
          -
        • Semantic search
        • +
        • Semantic search
      • -
      • keyword_search +
      • keyword_search
          -
        • Keyword-based search
        • +
        • Keyword-based search
      • -
      • attribute_search +
      • attribute_search
          -
        • Attribute-specific search
        • +
        • Attribute-specific search
      • -
      • search_suggestion +
      • search_suggestion
          -
        • Search syntax helper
        • +
        • Search syntax helper
      • -
      • read_note +
      • read_note
          -
        • Read note content (helps the LLM read Notes)
        • +
        • Read note content (helps the LLM read Notes)
      • -
      • create_note +
      • create_note
          -
        • Create a Note
        • +
        • Create a Note
      • -
      • update_note +
      • update_note
          -
        • Update a Note
        • +
        • Update a Note
      • -
      • manage_attributes +
      • manage_attributes
          -
        • Manage attributes on a Note
        • +
        • Manage attributes on a Note
      • -
      • manage_relationships +
      • manage_relationships
          -
        • Manage the various relationships between Notes
        • +
        • Manage the various relationships between Notes
      • -
      • extract_content +
      • extract_content
          -
        • Used to smartly extract content from a Note
        • +
        • Used to smartly extract content from a Note
      • -
      • calendar_integration +
      • calendar_integration
          -
        • Used to find date notes, create date notes, get the daily note, etc.
        • +
        • Used to find date notes, create date notes, get the daily note, etc.
      @@ -145,17 +144,18 @@ class="image image_resized" style="width:74.04%;">

      You don't need to tell the LLM to execute a certain tool, it should “smartly” call tools and automatically execute them as needed.

      Overview

      -

      Now that you know about embeddings and tools, you can just go ahead and - use the “Chat with Notes” button, where you can go ahead and start chatting!:

      -
      +

      To start, simply press the Chat with Notes button in the  + Launch Bar.

      +
      -
      -

      If you don't see the “Chat with Notes” button on your side launchbar, - you might need to move it from the “Available Launchers” section to the - “Visible Launchers” section:

      -
      - -
      \ No newline at end of file +
      +

      If you don't see the button in the Launch Bar, + you might need to move it from the Available Launchers section to + the Visible Launchers section:

      +
      + +
      \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Attributes.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Attributes.html index 8f28f72f4..d46a3e51c 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Attributes.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Attributes.html @@ -8,7 +8,7 @@
    • Labels can be used for a variety of purposes, such as storing metadata or configuring - the behaviour of notes. Labels are also searchable, enhancing note retrieval.

      + the behavior of notes. Labels are also searchable, enhancing note retrieval.

      For more information, including predefined labels, see Labels.

    • @@ -21,7 +21,7 @@ class="reference-link" href="#root/_help_Cq5X6iKQop6R">Relations.

      -

      These attributes play a crucial role in organizing, categorising, and +

      These attributes play a crucial role in organizing, categorizing, and enhancing the functionality of notes.

      Viewing the list of attributes

      Both the labels and relations for the current note are displayed in the Owned Attributes section diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Custom Request Handler.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Custom Request Handler.html index d7068f7eb..196996eed 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Custom Request Handler.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Custom Request Handler.html @@ -11,7 +11,7 @@ const {secret, title, content} = req.body; if (req.method == 'POST' && secret === 'secret-password') { // notes must be saved somewhere in the tree hierarchy specified by a parent note. // This is defined by a relation from this code note to the "target" parent note - // alternetively you can just use constant noteId for simplicity (get that from "Note Info" dialog of the desired parent note) + // alternatively you can just use constant noteId for simplicity (get that from "Note Info" dialog of the desired parent note) const targetParentNoteId = api.currentNote.getRelationValue('targetNote'); const {note} = api.createTextNote(targetParentNoteId, title, content); @@ -30,7 +30,7 @@ else { be saved

    Explanation

    -

    Let's test this by using an HTTP client to send a request:

    POST http://my.trilium.org/custom/create-note
    +

    Let's test this by using an HTTP client to send a request:

    POST http://your-trilium-server/custom/create-note
     Content-Type: application/json
     
     {
    @@ -64,12 +64,12 @@ Content-Type: application/json
       can always look into its documentation for
       details.

    Parameters

    -

    REST request paths often contain parameters in the URL, e.g.:

    http://my.trilium.org/custom/notes/123
    +

    REST request paths often contain parameters in the URL, e.g.:

    http://your-trilium-server/custom/notes/123

    The last part is dynamic so the matching of the URL must also be dynamic - for this reason the matching is done with regular expressions. Following customRequestHandler value would match it:

    notes/([0-9]+)

    Additionally, this also defines a matching group with the use of parenthesis which then makes it easier to extract the value. The matched groups are available in api.pathParams:

    const noteId = api.pathParams[0];
    -

    Often you also need query params (as in e.g. http://my.trilium.org/custom/notes?noteId=123), +

    Often you also need query params (as in e.g. http://your-trilium-server/custom/notes?noteId=123), you can get those with standard express req.query.noteId.

    \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Nightly release.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Nightly release.html new file mode 100644 index 000000000..d3cdc2008 --- /dev/null +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Nightly release.html @@ -0,0 +1,35 @@ +

    Nightly releases are versions built every day, containing the latest improvements + and bugfixes, directly from the main development branch. These versions + are generally useful in preparation for a release, to ensure that there + are no significant bugs that need to be addressed first, or they can be + used to confirm whether a particular bug is fixed or feature is well implemented.

    +

    Regarding the stability

    +

    Despite being on a development branch, generally the main branch is pretty + stable since PRs are tested before they are merged. If you notice any issues, + feel free to report them either via a ticket or via the Matrix.

    +

    Downloading the nightly release manually

    +

    Go to github.com/TriliumNext/Trilium/releases/tag/nightly and + look for the artifacts starting with TriliumNotes-main. Choose + the appropriate one for your platform (e.g. windows-x64.zip).

    +

    Depending on your use case, you can either test the portable version or + even use the installer.

    + + +

    Automatically download and install the latest nightly

    +

    This is pretty useful if you are a beta tester that wants to periodically + update their version:

    +

    On Ubuntu:

    #!/usr/bin/env bash
    +
    +name=TriliumNotes-linux-x64-nightly.deb
    +rm -f $name*
    +wget https://github.com/TriliumNext/Trilium/releases/download/nightly/$name
    +sudo apt-get install ./$name
    +rm $name
    \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Read-only database.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Read-only database.html new file mode 100644 index 000000000..e170c6fe9 --- /dev/null +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Read-only database.html @@ -0,0 +1,42 @@ + +

    The read-only database is an alternative to Sharing notes. + Although the share functionality works pretty well to publish pages to + the Internet in a wiki, blog-like format it does not offer the full functionality + behind Trilium (such as the advanced Search or + the interactivity behind Collections or + the various Note Types).

    +

    When the database is in read-only mode, the Trilium application can be + used as normal, but editing is disabled and changes are made in-memory + only.

    +

    What it does

    +
      +
    • All notes are read-only, without the possibility of editing them.
    • +
    • Features that would normally alter the database such as the list of recent + notes are disabled.
    • +
    +

    Limitations

    +
      +
    • Some features might “slip through” and still end up creating a note, for + example. +
        +
      • However, the database is still read-only, so all modifications will be + reset if the server is restarted.
      • +
      • Whenever this occurs, ERROR: read-only DB ignored will be shown + in the logs.
      • +
      +
    • +
    +

    Setting a database as read-only

    +

    First, make sure the database is initialized (e.g. the first set up is + complete). Then modify the config.ini by + looking for the [General] section and adding a new readOnly field:

    [General]
    +readOnly=true
    +

    If your server is already running, restart it to apply the changes.

    +

    Similarly, to disable read-only remove the line or set it to false.

    \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Safe mode.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Safe mode.html index a169f3800..87c50d2b7 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Safe mode.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Safe mode.html @@ -4,12 +4,9 @@ script to enable it.

    What it does:

      -
    • Disables customWidget launcher types in app/widgets/containers/launcher.js.
    • -
    • Disables the running of mobileStartup or frontendStartup scripts.
    • -
    • Displays the root note instead of the previously saved session.
    • -
    • Disables the running of backendStartup, hourly, daily scripts - and checks for the hidden subtree.
    • +
    • Disables customWidget launcher types in app/widgets/containers/launcher.js.
    • +
    • Disables the running of mobileStartup or frontendStartup scripts.
    • +
    • Displays the root note instead of the previously saved session.
    • +
    • Disables the running of backendStartup, hourly, daily scripts + and checks for the hidden 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/Navigation/Search.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Navigation/Search.html index 5a93064e8..0911a8b6c 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Navigation/Search.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Navigation/Search.html @@ -21,7 +21,7 @@
    1. Set the text to search for in the Search string field.
        -
      1. Apart from searching for words ad-literam, there is also the possibility +
      2. Apart from searching for words literally, there is also the possibility to search for attributes or properties of notes.
      3. See the examples below for more information.
      diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes.html index 26efd0947..42e484e70 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes.html @@ -31,7 +31,7 @@ and you will see a list of all modified notes including the deleted ones. Notes available for undeletion have a link to do so. This is kind of "trash can" functionality known from e.g. Windows.

      -

      Clicking an undelete will recover the note, it's content and attributes +

      Clicking an undelete will recover the note, its content and attributes - note should be just as before being deleted. This action will also undelete note's children which have been deleted in the same action.

      To be able to undelete a note, it is necessary that deleted note's parent diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.html index 96db62c4b..e23f83d72 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.html @@ -29,7 +29,7 @@

    2. Editable changes whether the current note:
      • Enters read-only mode automatically if - the note is too big (default behaviour).
      • + the note is too big (default behavior).
      • Is always in read-only mode (however it can still be edited temporarily).
      • Is always editable, regardless of its size.
      diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections.html index fa40dcfbd..3aaad0a7e 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections.html @@ -1,5 +1,5 @@ -

      Collections are a unique type of notes that don't have a content, but - instead display its child notes in various presentation methods.

      +

      Collections are a unique type of note that don't have content, but instead + display their child notes in various presentation methods.

      Main collections

      @@ -94,7 +94,7 @@ in the Ribbon.

      Archived notes

      By default, archived notes will not be - shown in collections. This behaviour can be changed by going to Collection Properties in + shown in collections. This behavior can be changed by going to Collection Properties in the Ribbon and checking Show archived notes.

      Archived notes will be generally indicated by being greyed out as opposed diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Data directory.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Data directory.html index b5a486848..ad81d00c1 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Data directory.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Data directory.html @@ -1,12 +1,12 @@

      Data directory contains:

        -
      • document.db - database +
      • document.db - database
      • -
      • config.ini - instance level settings like port on which the +
      • config.ini - instance level settings like port on which the Trilium application runs
      • -
      • backup - contains automatically backup of +
      • backup - contains automatically backup of documents
      • -
      • log - contains application log files
      • +
      • log - contains application log files

      Location of the data directory

      Easy way how to find out which data directory Trilium uses is to look @@ -18,30 +18,42 @@

      Data directory is normally named trilium-data and it is stored in:

        -
      • /home/[user]/.local/share for Linux
      • -
      • C:\Users\[user]\AppData\Roaming for Windows Vista and up
      • -
      • /Users/[user]/Library/Application Support for Mac OS
      • -
      • user's home is a fallback if some of the paths above don't exist
      • -
      • user's home is also a default setup for [[docker|Docker server installation]]
      • +
      • /home/[user]/.local/share for Linux
      • +
      • C:\Users\[user]\AppData\Roaming for Windows Vista and up
      • +
      • /Users/[user]/Library/Application Support for Mac OS
      • +
      • user's home is a fallback if some of the paths above don't exist
      • +
      • user's home is also a default setup for [[docker|Docker server installation]]

      If you want to back up your Trilium data, just backup this single directory - it contains everything you need.

      Changing the location of data directory

      If you want to use some other location for the data directory than the - default one, you may change it via TRILIUM_DATA_DIR environment variable - to some other location:

      + default one, you may change it via TRILIUM_DATA_DIR environment + variable to some other location:

      +

      Windows

      +
        +
      1. Press the Windows key on your keyboard.
      2. +
      3. Search and select “Edit the system variables”.
      4. +
      5. Press the “Environment Variables…” button in the bottom-right of the newly + opened screen.
      6. +
      7. On the top section ("User variables for [user]"), press the “New…” button.
      8. +
      9. In the Variable name field insert TRILIUM_DATA_DIR.
      10. +
      11. Press the Browse Directory… button and select the new directory + where to store the database.
      12. +
      13. Close all the windows by pressing the OK button for each of them.
      14. +

      Linux

      export TRILIUM_DATA_DIR=/home/myuser/data/my-trilium-data

      Mac OS X

      You need to create a .plist file under ~/Library/LaunchAgents to load it properly each login.

      To load it manually, you need to use launchctl setenv TRILIUM_DATA_DIR <yourpath>

      -

      Here is a pre-defined template, where you just need to add your path to:

      
      -
      -
      -
      -    
      -        Label
      +

      Here is a pre-defined template, where you just need to add your path to:

              Label
               set.trilium.env
               RunAtLoad
               
      @@ -50,76 +62,75 @@
                   launchctl
                   setenv
                   TRILIUM_DATA_DIR
      -            /Users/YourUserName/Library/Application Support/trilium-data
      -        
      -    
      -
      + /Users/YourUserName/Library/Application Support/trilium-data

      Create a script to run with specific data directory

      An alternative to globally setting environment variable is to run only the Trilium Notes with this environment variable. This then allows for different setup styles like two database instances or "portable" installation.

      -

      To do this in unix based systems simply run trilium like this:

      TRILIUM_DATA_DIR=/home/myuser/data/my-trilium-data trilium
      +

      To do this in Unix-based systems simply run trilium like this:

      TRILIUM_DATA_DIR=/home/myuser/data/my-trilium-data trilium

      You can then save the above command as a shell script on your path for convenience.

      Fine-grained directory/path location

      Apart from the data directory, some of the subdirectories of it can be moved elsewhere by changing an environment variable:

      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      Environment variableDefault valueDescription
      TRILIUM_DOCUMENT_PATH - ${TRILIUM_DATA_DIR}/document.db - Path to the Database (storing - all notes and metadata).
      TRILIUM_BACKUP_DIR - ${TRILIUM_DATA_DIR}/backup - Directory where automated Backup databases - are stored.
      TRILIUM_LOG_DIR - ${TRILIUM_DATA_DIR}/log - Directory where daily Backend (server) logs are - stored.
      TRILIUM_TMP_DIR - ${TRILIUM_DATA_DIR}/tmp - Directory where temporary files are stored (for example when opening in - an external app).
      TRILIUM_ANONYMIZED_DB_DIR - ${TRILIUM_DATA_DIR}/anonymized-db - Directory where a Anonymized Database is - stored.
      TRILIUM_CONFIG_INI_PATH - ${TRILIUM_DATA_DIR}/config.ini - Path to Configuration (config.ini or environment variables) file.
      \ No newline at end of file +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Environment variableDefault valueDescription
      TRILIUM_DOCUMENT_PATH + ${TRILIUM_DATA_DIR}/document.db + Path to the Database (storing + all notes and metadata).
      TRILIUM_BACKUP_DIR + ${TRILIUM_DATA_DIR}/backup + Directory where automated Backup databases + are stored.
      TRILIUM_LOG_DIR + ${TRILIUM_DATA_DIR}/log + Directory where daily Backend (server) logs are + stored.
      TRILIUM_TMP_DIR + ${TRILIUM_DATA_DIR}/tmp + Directory where temporary files are stored (for example when opening in + an external app).
      TRILIUM_ANONYMIZED_DB_DIR + ${TRILIUM_DATA_DIR}/anonymized-db + Directory where a Anonymized Database is + stored.
      TRILIUM_CONFIG_INI_PATH + ${TRILIUM_DATA_DIR}/config.ini + Path to Configuration (config.ini or environment variables) file.
      +
      \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Desktop Installation.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Desktop Installation.html index b213daf6e..5adf8dbe1 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Desktop Installation.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Desktop Installation.html @@ -27,6 +27,6 @@ any startup scripts that might cause the application to crash.
    3. Synchronization

      -

      For Trilium desktp users who wish to synchronize their data with a server +

      For Trilium desktop users who wish to synchronize their data with a server instance, refer to the Synchronization guide for detailed instructions.

      \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation.html index 0c34a40ae..dfaa68a0d 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation.html @@ -40,7 +40,7 @@

      Disabling / Modifying the Upload Limit

      If you're running into the 250MB limit imposed on the server by default, and you'd like to increase the upload limit, you can set the TRILIUM_NO_UPLOAD_LIMIT environment - variable to true disable it completely:

      export TRILIUM_NO_UPLOAD_LIMIT=true 
      + variable to true to disable it completely:

      export TRILIUM_NO_UPLOAD_LIMIT=true 

      Or, if you'd simply like to increase the upload limit size to something beyond 250MB, you can set the MAX_ALLOWED_FILE_SIZE_MB environment variable to something larger than the integer 250 (e.g. 450 in diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types.html index 9c69cade3..1369ccfa6 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types.html @@ -1,5 +1,5 @@ -

      One core features of Trilium is that it supports multiple types of notes, - depending on the need.

      +

      One of the core features of Trilium is that it supports multiple types + of notes, depending on the need.

      Creating a new note with a different type via the note tree

      The default note type in Trilium (e.g. when creating a new note) is  Script API provide extra functionality.

      -

      Scripting

      +

      Architecture Overview

      To go further I must explain basic architecture of Trilium - in its essence it is a classic web application - it has these two main components:

        @@ -14,8 +14,8 @@

      So we have frontend and backend, each with their own set of responsibilities, but their common feature is that they both run JavaScript code. Add to - this the fact, that we're able to create JavaScript [[code notes]] and - we're onto something.

      + this the fact, that we're able to create JavaScript code notes and we're onto something.

      Use cases

      • "New Task" launcher button diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Events.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Backend scripts/Events.html similarity index 100% rename from apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Events.html rename to apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Backend scripts/Events.html diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Backend scripts/Server-side imports.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Backend scripts/Server-side imports.html new file mode 100644 index 000000000..7820ccfe2 --- /dev/null +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Backend scripts/Server-side imports.html @@ -0,0 +1,7 @@ +

        Older versions of Trilium Notes allowed the use of Common.js module imports + inside backend scripts, such as:

        const isBetween = require('dayjs/plugin/isBetween')
        +api.dayjs.extend(isBetween)
        +

        For newer versions, Node.js imports are not officially supported anymore, + since we've added a bundler which makes it more difficult to reuse dependencies.

        +

        Theoretically it's still possible to use imports by manually setting up + a node_modules in the server directory via npm or pnpm.

        \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Custom Widgets.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets.html similarity index 100% rename from apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Custom Widgets.html rename to apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets.html diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/CSS.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/CSS.html new file mode 100644 index 000000000..249da3ad3 --- /dev/null +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/CSS.html @@ -0,0 +1,9 @@ +

        In doRender():

        this.cssBlock(`#my-widget {
        +	position: absolute;
        +    bottom: 40px;
        +    left: 60px;
        +    z-index: 1;
        +}`)
        +
        +

        Reference: https://trilium.rocks/X7pxYpiu0lgU +

        \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.html new file mode 100644 index 000000000..7b571b628 --- /dev/null +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.html @@ -0,0 +1,30 @@ +
          +
        • doRender must not be overridden, instead doRenderBody() has + to be overridden.
        • +
        • parentWidget() must be set to “rightPane”.
        • +
        • widgetTitle() getter can optionally be overriden, otherwise + the widget will be displayed as “Untitled widget”.
        • +
        const template = `<div>Hi</div>`;
        +
        +class ToDoListWidget extends api.RightPanelWidget {
        +    
        +    get widgetTitle() {
        +        return "Title goes here";
        +    }
        +        
        +    get parentWidget() { return "right-pane" }
        +    
        +    doRenderBody() {
        +        this.$body.empty().append($(template));
        +    }   
        +    
        +    async refreshWithNote(note) {
        +        this.toggleInt(false);                
        +        this.triggerCommand("reEvaluateRightPaneVisibility");
        +        this.toggleInt(true);
        +        this.triggerCommand("reEvaluateRightPaneVisibility");
        +    }
        +}
        +
        +module.exports = new ToDoListWidget();
        +

        The implementation is in src/public/app/widgets/right_panel_widget.js.

        \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Custom Widgets/Widget Basics.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics.html similarity index 82% rename from apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Custom Widgets/Widget Basics.html rename to apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics.html index 273dbaae6..84a15c29e 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Custom Widgets/Widget Basics.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics.html @@ -87,5 +87,17 @@ module.exports = new MyWidget();
    } module.exports = new MyWidget();
    -

    Reload the application one last time. When you click the button, a "Hello - World!" message should appear, confirming that your widget is fully functional.

    \ No newline at end of file +

    parentWidget() can be given the following values:

    +
      +
    • left-pane - This renders the widget on the left side of the + screen where the note tree lives.
    • +
    • center-pane - This renders the widget in the center of the + layout in the same location that notes and splits appear.
    • +
    • note-detail-pane - This renders the widget with the + note in the center pane. This means it can appear multiple times with splits.
    • +
    • right-pane - This renders the widget to the right of any opened + notes.
    • +
    +

    Reload the application one last time. + When you click the button, a "Hello World!" message should appear, confirming + that your widget is fully functional.

    \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Custom Widgets/Word count widget.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget.html similarity index 100% rename from apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Custom Widgets/Word count widget.html rename to apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget.html diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Custom Widgets/Word count widget_image.png b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget_image.png similarity index 100% rename from apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Custom Widgets/Word count widget_image.png rename to apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget_image.png diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Examples/Downloading responses from Goo.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Examples/Downloading responses from Goo.html similarity index 100% rename from apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Examples/Downloading responses from Goo.html rename to apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Examples/Downloading responses from Goo.html diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Examples/New Task launcher button.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button.html similarity index 100% rename from apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Examples/New Task launcher button.html rename to apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button.html diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Examples/New Task launcher button_i.png b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button_i.png similarity index 100% rename from apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Examples/New Task launcher button_i.png rename to apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button_i.png diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Examples/Using promoted attributes .png b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes .png similarity index 100% rename from apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Examples/Using promoted attributes .png rename to apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes .png diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Examples/Using promoted attributes to c.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes to c.html similarity index 100% rename from apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Examples/Using promoted attributes to c.html rename to apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes to c.html diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Troubleshooting.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Troubleshooting.html index cc53090a9..11b6cdc3c 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Troubleshooting.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Troubleshooting.html @@ -1,4 +1,5 @@ -

    As Trilium is currently in beta, encountering bugs is to be expected.

    +

    While Trilium is actively maintained and stable, encountering bugs is + possible.

    General Quick Fix

    The first step in troubleshooting is often a restart.

    If you experience an UI issue, the frontend may have entered an inconsistent @@ -15,7 +16,7 @@ variable to reset the open tabs to a single specified note ID (e.g., root). In Linux, you can set it as follows:

    TRILIUM_START_NOTE_ID=root ./trilium

    Broken Script Prevents Application Startup

    -

    If a custom script causes Triliumto crash, and it is set as a startup +

    If a custom script causes Trilium to crash, and it is set as a startup script or in an active custom widget, start Triliumin "safe mode" to prevent any custom scripts from executing:

    TRILIUM_SAFE_MODE=true ./trilium

    Depending on your Trilium distribution, you may have pre-made scripts diff --git a/apps/server/src/assets/translations/it/server.json b/apps/server/src/assets/translations/it/server.json index 1b88e03d7..0b64f0fee 100644 --- a/apps/server/src/assets/translations/it/server.json +++ b/apps/server/src/assets/translations/it/server.json @@ -420,7 +420,7 @@ "end-time": "Ora di fine", "geolocation": "Geolocalizzazione", "built-in-templates": "Modelli integrati", - "board": "Tavola", + "board": "Kanban Board", "status": "Stato", "board_note_first": "Prima nota", "board_note_second": "Seconda nota", diff --git a/apps/server/src/assets/translations/tw/server.json b/apps/server/src/assets/translations/tw/server.json index 8d29cc64f..33c9faa8c 100644 --- a/apps/server/src/assets/translations/tw/server.json +++ b/apps/server/src/assets/translations/tw/server.json @@ -417,7 +417,7 @@ "end-time": "結束時間", "geolocation": "地理位置", "built-in-templates": "內建模版", - "board": "儀表板", + "board": "看板", "status": "狀態", "board_note_first": "第一個筆記", "board_note_second": "第二個筆記", diff --git a/apps/server/src/routes/api/branches.ts b/apps/server/src/routes/api/branches.ts index 810deaba7..73ce03a7a 100644 --- a/apps/server/src/routes/api/branches.ts +++ b/apps/server/src/routes/api/branches.ts @@ -270,6 +270,38 @@ function setPrefix(req: Request) { branch.save(); } +function setPrefixBatch(req: Request) { + const { branchIds, prefix } = req.body; + + if (!Array.isArray(branchIds)) { + throw new ValidationError("branchIds must be an array"); + } + + // Validate that prefix is a string or null/undefined to prevent prototype pollution + if (prefix !== null && prefix !== undefined && typeof prefix !== 'string') { + throw new ValidationError("prefix must be a string or null"); + } + + const normalizedPrefix = utils.isEmptyOrWhitespace(prefix) ? null : prefix; + let updatedCount = 0; + + for (const branchId of branchIds) { + const branch = becca.getBranch(branchId); + if (branch) { + branch.prefix = normalizedPrefix; + branch.save(); + updatedCount++; + } else { + log.info(`Branch ${branchId} not found, skipping prefix update`); + } + } + + return { + success: true, + count: updatedCount + }; +} + export default { moveBranchToParent, moveBranchBeforeNote, @@ -277,5 +309,6 @@ export default { setExpanded, setExpandedForSubtree, deleteBranch, - setPrefix + setPrefix, + setPrefixBatch }; diff --git a/apps/server/src/routes/routes.ts b/apps/server/src/routes/routes.ts index 9074789f2..78a1380b7 100644 --- a/apps/server/src/routes/routes.ts +++ b/apps/server/src/routes/routes.ts @@ -154,6 +154,7 @@ function register(app: express.Application) { apiRoute(PUT, "/api/branches/:branchId/expanded-subtree/:expanded", branchesApiRoute.setExpandedForSubtree); apiRoute(DEL, "/api/branches/:branchId", branchesApiRoute.deleteBranch); apiRoute(PUT, "/api/branches/:branchId/set-prefix", branchesApiRoute.setPrefix); + apiRoute(PUT, "/api/branches/set-prefix-batch", branchesApiRoute.setPrefixBatch); apiRoute(GET, "/api/notes/:noteId/attachments", attachmentsApiRoute.getAttachments); apiRoute(PST, "/api/notes/:noteId/attachments", attachmentsApiRoute.saveAttachment); diff --git a/apps/server/src/www.ts b/apps/server/src/www.ts index 7f3445312..130d3a380 100644 --- a/apps/server/src/www.ts +++ b/apps/server/src/www.ts @@ -158,13 +158,11 @@ function startHttpServer(app: Express) { // Not all situations require showing an error dialog. When Trilium is already open, // clicking the shortcut, the software icon, or the taskbar icon, or when creating a new window, // should simply focus on the existing window or open a new one, without displaying an error message. - if ("code" in error && error.code == "EADDRINUSE") { - if (process.argv.includes("--new-window") || !app.requestSingleInstanceLock()) { - console.error(message); - process.exit(1); - } + if ("code" in error && error.code === "EADDRINUSE" && (process.argv.includes("--new-window") || !app.requestSingleInstanceLock())) { + console.error(message); + } else { + dialog.showErrorBox("Error while initializing the server", message); } - dialog.showErrorBox("Error while initializing the server", message); process.exit(1); }); } else { diff --git a/apps/website/package.json b/apps/website/package.json index 51a78d27c..e3bbd8c4b 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -14,11 +14,11 @@ "preact": "10.27.2", "preact-iso": "2.11.0", "preact-render-to-string": "6.6.3", - "react-i18next": "16.2.3" + "react-i18next": "16.2.4" }, "devDependencies": { "@preact/preset-vite": "2.10.2", - "eslint": "9.39.0", + "eslint": "9.39.1", "eslint-config-preact": "2.0.0", "typescript": "5.9.3", "user-agent-data-types": "0.4.2", diff --git a/apps/website/src/translations/it/translation.json b/apps/website/src/translations/it/translation.json index 03792e5ed..915396c1a 100644 --- a/apps/website/src/translations/it/translation.json +++ b/apps/website/src/translations/it/translation.json @@ -70,7 +70,7 @@ "calendar_description": "Organizza i tuoi eventi personali o professionali utilizzando un calendario, con supporto per eventi di un giorno intero o di più giorni. Visualizza i tuoi eventi a colpo d'occhio con le viste settimanale, mensile e annuale. Interazione semplice per aggiungere o trascinare eventi.", "table_title": "Tabella", "table_description": "Visualizza e modifica le informazioni relative alle note in una struttura tabellare, con vari tipi di colonne quali testo, numeri, caselle di controllo, data e ora, collegamenti e colori, oltre al supporto per le relazioni. Facoltativamente, è possibile visualizzare le note all'interno di una gerarchia ad albero all'interno della tabella.", - "board_title": "Board", + "board_title": "Kanban Board", "board_description": "Organizza le tue attività o lo stato dei tuoi progetti in una lavagna Kanban con un modo semplice per creare nuovi elementi e colonne e modificare facilmente il loro stato trascinandoli sulla lavagna.", "geomap_title": "Geomappa", "geomap_description": "Pianifica le tue vacanze o segna i tuoi punti di interesse direttamente su una mappa geografica utilizzando indicatori personalizzabili. Visualizza le tracce GPX registrate per seguire gli itinerari.", diff --git a/apps/website/src/translations/zh-Hant/translation.json b/apps/website/src/translations/zh-Hant/translation.json index 79ac2185b..f5ef4764b 100644 --- a/apps/website/src/translations/zh-Hant/translation.json +++ b/apps/website/src/translations/zh-Hant/translation.json @@ -70,7 +70,7 @@ "calendar_description": "使用行事曆規劃個人或專業活動,支援全天及多日活動。透過週、月、年檢視模式,一覽所有活動。通過簡單互動即可新增或拖曳活動。", "table_title": "表格", "table_description": "以表格結構顯示並編輯筆記資訊,支援多種欄位類型,包括文字、數字、核取方塊、日期與時間、連結及顏色,並支援關聯功能。可選擇性地在表格內以樹狀層級結構顯示筆記內容。", - "board_title": "儀表板", + "board_title": "看板", "board_description": "將您的任務或專案狀態整理成看板,輕鬆建立新項目與欄位,並透過在看板上拖曳即可簡單變更狀態。", "geomap_title": "地理地圖", "geomap_description": "使用可自訂的標記,直接在地圖上規劃您的假期行程或標記感興趣的地點。顯示已記錄的GPX軌跡,以便追蹤行程路線。", diff --git a/apps/website/tsconfig.json b/apps/website/tsconfig.json index 4d67635d7..68e45adef 100644 --- a/apps/website/tsconfig.json +++ b/apps/website/tsconfig.json @@ -10,7 +10,8 @@ "jsxImportSource": "preact", "skipLibCheck": true, "types": [ - "vite/client" + "vite/client", + "vitest/config" ], "paths": { "react": ["../../node_modules/preact/compat/"], diff --git a/docs/Developer Guide/!!!meta.json b/docs/Developer Guide/!!!meta.json index f384978f2..63e4d0cc4 100644 --- a/docs/Developer Guide/!!!meta.json +++ b/docs/Developer Guide/!!!meta.json @@ -15,6 +15,20 @@ "type": "text", "mime": "text/html", "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "T2W7WCZrYZBU", + "isInheritable": false, + "position": 10 + }, + { + "type": "relation", + "name": "internalLink", + "value": "cxfTSHIUQtt2", + "isInheritable": false, + "position": 20 + }, { "type": "label", "name": "label:shareAlias", @@ -56,6 +70,13 @@ "type": "text", "mime": "text/html", "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "TLXJwBDo8Rdv", + "isInheritable": false, + "position": 10 + }, { "type": "label", "name": "iconClass", @@ -69,13 +90,6 @@ "value": "environment-setup", "isInheritable": false, "position": 20 - }, - { - "type": "relation", - "name": "internalLink", - "value": "TLXJwBDo8Rdv", - "isInheritable": false, - "position": 30 } ], "format": "markdown", @@ -96,6 +110,13 @@ "type": "text", "mime": "text/html", "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "a0mkxxB4Uvbf", + "isInheritable": false, + "position": 10 + }, { "type": "label", "name": "iconClass", @@ -109,72 +130,138 @@ "value": "project-structure", "isInheritable": false, "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Project Structure.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "MhwWMgxwDTZL", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL" + ], + "title": "Architecture", + "notePosition": 280, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "architecture", + "isInheritable": false, + "position": 20 }, { - "type": "relation", - "name": "internalLink", - "value": "a0mkxxB4Uvbf", + "type": "label", + "name": "iconClass", + "value": "bx bx-arch", "isInheritable": false, "position": 30 } ], "format": "markdown", - "dataFileName": "Project Structure.md", + "dataFileName": "Architecture.md", "attachments": [], - "dirFileName": "Project Structure", + "dirFileName": "Architecture", "children": [ { "isClone": false, - "noteId": "Jg7clqogFOyD", + "noteId": "dsMq2EIOMOBU", "notePath": [ "jdjRLhLV3TtI", - "cxfTSHIUQtt2", - "Jg7clqogFOyD" + "MhwWMgxwDTZL", + "dsMq2EIOMOBU" ], - "title": "CKEditor", + "title": "Frontend", "notePosition": 10, "prefix": null, "isExpanded": false, "type": "text", "mime": "text/html", "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "BRhQZHgwaGyw", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "iconClass", - "value": "bx bx-package", - "isInheritable": false, - "position": 10 - }, { "type": "label", "name": "shareAlias", - "value": "ckeditor", + "value": "frontend", "isInheritable": false, "position": 20 } ], "format": "markdown", - "dataFileName": "CKEditor.md", + "dataFileName": "Frontend.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "tsswRlmHEnYW", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "tsswRlmHEnYW" + ], + "title": "Backend", + "notePosition": 20, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "backend", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Backend.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "pRZhrVIGCbMu", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "pRZhrVIGCbMu" + ], + "title": "Database", + "notePosition": 40, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "database", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Database.md", "attachments": [], - "dirFileName": "CKEditor", + "dirFileName": "Database", "children": [ { "isClone": false, - "noteId": "BRhQZHgwaGyw", + "noteId": "vNMojjUN76jc", "notePath": [ "jdjRLhLV3TtI", - "cxfTSHIUQtt2", - "Jg7clqogFOyD", - "BRhQZHgwaGyw" + "MhwWMgxwDTZL", + "pRZhrVIGCbMu", + "vNMojjUN76jc" ], - "title": "Plugin migration guide", + "title": "Database structure", "notePosition": 10, "prefix": null, "isExpanded": false, @@ -184,16 +271,662 @@ { "type": "label", "name": "shareAlias", - "value": "plugin-migration", + "value": "tables", "isInheritable": false, "position": 20 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-table", + "isInheritable": false, + "position": 30 } ], "format": "markdown", - "dataFileName": "Plugin migration guide.md", - "attachments": [] + "attachments": [], + "dirFileName": "Database structure", + "children": [ + { + "isClone": false, + "noteId": "e6GnYOXeIWjg", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "pRZhrVIGCbMu", + "vNMojjUN76jc", + "e6GnYOXeIWjg" + ], + "title": "attachments", + "notePosition": 20, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "DSkl8C325tEC", + "isInheritable": false, + "position": 10 + }, + { + "type": "relation", + "name": "internalLink", + "value": "UvXpeSqfYc6d", + "isInheritable": false, + "position": 20 + }, + { + "type": "relation", + "name": "internalLink", + "value": "VIcWnKGs0sMh", + "isInheritable": false, + "position": 30 + }, + { + "type": "relation", + "name": "internalLink", + "value": "tM3rIZQzlum4", + "isInheritable": false, + "position": 40 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-table", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "attachments", + "isInheritable": false, + "position": 50 + } + ], + "format": "markdown", + "dataFileName": "attachments.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "ciL84vNBNi9y", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "pRZhrVIGCbMu", + "vNMojjUN76jc", + "ciL84vNBNi9y" + ], + "title": "attributes", + "notePosition": 30, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "DSkl8C325tEC", + "isInheritable": false, + "position": 10 + }, + { + "type": "relation", + "name": "internalLink", + "value": "tM3rIZQzlum4", + "isInheritable": false, + "position": 20 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-table", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "attributes", + "isInheritable": false, + "position": 40 + } + ], + "format": "markdown", + "dataFileName": "attributes.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "VIcWnKGs0sMh", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "pRZhrVIGCbMu", + "vNMojjUN76jc", + "VIcWnKGs0sMh" + ], + "title": "blobs", + "notePosition": 40, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "iconClass", + "value": "bx bx-table", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "blobs", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "blobs.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "GskLPkgY5n6E", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "pRZhrVIGCbMu", + "vNMojjUN76jc", + "GskLPkgY5n6E" + ], + "title": "branches", + "notePosition": 50, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "DSkl8C325tEC", + "isInheritable": false, + "position": 10 + }, + { + "type": "relation", + "name": "internalLink", + "value": "h8AsuFjSD4fB", + "isInheritable": false, + "position": 20 + }, + { + "type": "relation", + "name": "internalLink", + "value": "tM3rIZQzlum4", + "isInheritable": false, + "position": 30 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-table", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "branches", + "isInheritable": false, + "position": 40 + } + ], + "format": "markdown", + "dataFileName": "branches.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "ohhExR078MPU", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "pRZhrVIGCbMu", + "vNMojjUN76jc", + "ohhExR078MPU" + ], + "title": "entity_changes", + "notePosition": 51, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "iconClass", + "value": "bx bx-table", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "entity-changes", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "entity_changes.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "bRqbIg633nCs", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "pRZhrVIGCbMu", + "vNMojjUN76jc", + "bRqbIg633nCs" + ], + "title": "etapi_tokens", + "notePosition": 52, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "tM3rIZQzlum4", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-table", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "etapi-tokens", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "etapi_tokens.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "DSkl8C325tEC", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "pRZhrVIGCbMu", + "vNMojjUN76jc", + "DSkl8C325tEC" + ], + "title": "notes", + "notePosition": 53, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "VIcWnKGs0sMh", + "isInheritable": false, + "position": 10 + }, + { + "type": "relation", + "name": "internalLink", + "value": "UvXpeSqfYc6d", + "isInheritable": false, + "position": 20 + }, + { + "type": "relation", + "name": "internalLink", + "value": "tM3rIZQzlum4", + "isInheritable": false, + "position": 30 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-table", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "notes", + "isInheritable": false, + "position": 40 + } + ], + "format": "markdown", + "dataFileName": "notes.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "4oeftEmy77Bt", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "pRZhrVIGCbMu", + "vNMojjUN76jc", + "4oeftEmy77Bt" + ], + "title": "options", + "notePosition": 54, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "iconClass", + "value": "bx bx-table", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "options", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "options.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "VyFirdgAOoh5", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "pRZhrVIGCbMu", + "vNMojjUN76jc", + "VyFirdgAOoh5" + ], + "title": "recent_notes", + "notePosition": 55, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "DSkl8C325tEC", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-table", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "recent-notes", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "recent_notes.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "s7ZBiaJVNumK", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "pRZhrVIGCbMu", + "vNMojjUN76jc", + "s7ZBiaJVNumK" + ], + "title": "revisions", + "notePosition": 56, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "DSkl8C325tEC", + "isInheritable": false, + "position": 10 + }, + { + "type": "relation", + "name": "internalLink", + "value": "VIcWnKGs0sMh", + "isInheritable": false, + "position": 20 + }, + { + "type": "relation", + "name": "internalLink", + "value": "UvXpeSqfYc6d", + "isInheritable": false, + "position": 30 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-table", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "revisions", + "isInheritable": false, + "position": 50 + } + ], + "format": "markdown", + "dataFileName": "revisions.md", + "attachments": [] + } + ] } ] + }, + { + "isClone": false, + "noteId": "Wxn82Em8B7U5", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "Wxn82Em8B7U5" + ], + "title": "APIs", + "notePosition": 50, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "api", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "APIs.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "Vk4zD1Iirarg", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "Vk4zD1Iirarg" + ], + "title": "Arhitecture Decision Records", + "notePosition": 60, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "Jg7clqogFOyD", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "adr", + "isInheritable": false, + "position": 30 + } + ], + "format": "markdown", + "dataFileName": "Arhitecture Decision Records.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "RHbKw3xiwk3S", + "notePath": [ + "jdjRLhLV3TtI", + "MhwWMgxwDTZL", + "RHbKw3xiwk3S" + ], + "title": "Security", + "notePosition": 80, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "security", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Security.md", + "attachments": [] + } + ] + }, + { + "isClone": false, + "noteId": "zdQzavvHDl1k", + "notePath": [ + "jdjRLhLV3TtI", + "zdQzavvHDl1k" + ], + "title": "Documentation", + "notePosition": 290, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "T2W7WCZrYZBU", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "documentation", + "isInheritable": false, + "position": 20 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-book-open", + "isInheritable": false, + "position": 30 + } + ], + "format": "markdown", + "dataFileName": "Documentation.md", + "attachments": [], + "dirFileName": "Documentation", + "children": [ + { + "isClone": false, + "noteId": "LjqM0VUL1CrU", + "notePath": [ + "jdjRLhLV3TtI", + "zdQzavvHDl1k", + "LjqM0VUL1CrU" + ], + "title": "Documentation references in the application", + "notePosition": 10, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "doc-references", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Documentation references in th.md", + "attachments": [] } ] }, @@ -205,7 +938,7 @@ "a0mkxxB4Uvbf" ], "title": "Building", - "notePosition": 280, + "notePosition": 300, "prefix": null, "isExpanded": false, "type": "text", @@ -246,25 +979,25 @@ "mime": "text/html", "attributes": [ { - "type": "label", - "name": "shareAlias", - "value": "dev-build", + "type": "relation", + "name": "internalLink", + "value": "mXFYlhuEr1mZ", "isInheritable": false, - "position": 20 + "position": 10 }, { "type": "relation", "name": "internalLink", "value": "T2W7WCZrYZBU", "isInheritable": false, - "position": 30 + "position": 20 }, { - "type": "relation", - "name": "internalLink", - "value": "mXFYlhuEr1mZ", + "type": "label", + "name": "shareAlias", + "value": "dev-build", "isInheritable": false, - "position": 40 + "position": 20 } ], "format": "markdown", @@ -402,40 +1135,298 @@ }, { "isClone": false, - "noteId": "zdQzavvHDl1k", + "noteId": "4nwtTJyjNDKd", "notePath": [ "jdjRLhLV3TtI", "a0mkxxB4Uvbf", - "zdQzavvHDl1k" + "4nwtTJyjNDKd" ], - "title": "Documentation", - "notePosition": 60, + "title": "Releasing a new version", + "notePosition": 70, "prefix": null, "isExpanded": false, "type": "text", "mime": "text/html", "attributes": [ { - "type": "label", - "name": "shareAlias", - "value": "documentation", + "type": "relation", + "name": "internalLink", + "value": "zdQzavvHDl1k", "isInheritable": false, - "position": 20 + "position": 10 }, { "type": "label", "name": "iconClass", - "value": "bx bx-book-open", + "value": "bx bx-rocket", "isInheritable": false, "position": 30 + }, + { + "type": "label", + "name": "shareAlias", + "value": "releasing", + "isInheritable": false, + "position": 40 } ], "format": "markdown", - "dataFileName": "Documentation.md", + "dataFileName": "Releasing a new version.md", "attachments": [] } ] }, + { + "isClone": false, + "noteId": "qalhAaJoQ7AN", + "notePath": [ + "jdjRLhLV3TtI", + "qalhAaJoQ7AN" + ], + "title": "Dependencies", + "notePosition": 320, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "iconClass", + "value": "bx bxs-component", + "isInheritable": false, + "position": 20 + }, + { + "type": "label", + "name": "shareAlias", + "value": "dependencies", + "isInheritable": false, + "position": 30 + } + ], + "format": "markdown", + "attachments": [], + "dirFileName": "Dependencies", + "children": [ + { + "isClone": false, + "noteId": "fa6hAJ9Ith3A", + "notePath": [ + "jdjRLhLV3TtI", + "qalhAaJoQ7AN", + "fa6hAJ9Ith3A" + ], + "title": "Per-dependency checks", + "notePosition": 10, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "Xfi1ScuBTKJf", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "updating-deps", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Per-dependency checks.md", + "attachments": [], + "dirFileName": "Per-dependency checks", + "children": [ + { + "isClone": false, + "noteId": "Xfi1ScuBTKJf", + "notePath": [ + "jdjRLhLV3TtI", + "qalhAaJoQ7AN", + "fa6hAJ9Ith3A", + "Xfi1ScuBTKJf" + ], + "title": "bettersqlite binaries", + "notePosition": 10, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "bettersqlite-binaries", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "bettersqlite binaries.md", + "attachments": [] + } + ] + }, + { + "isClone": false, + "noteId": "Jg7clqogFOyD", + "notePath": [ + "jdjRLhLV3TtI", + "qalhAaJoQ7AN", + "Jg7clqogFOyD" + ], + "title": "CKEditor", + "notePosition": 20, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "BRhQZHgwaGyw", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-package", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "ckeditor", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "CKEditor.md", + "attachments": [], + "dirFileName": "CKEditor", + "children": [ + { + "isClone": false, + "noteId": "BRhQZHgwaGyw", + "notePath": [ + "jdjRLhLV3TtI", + "qalhAaJoQ7AN", + "Jg7clqogFOyD", + "BRhQZHgwaGyw" + ], + "title": "Plugin migration guide", + "notePosition": 10, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "plugin-migration", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Plugin migration guide.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "5gBYmUqiupBl", + "notePath": [ + "jdjRLhLV3TtI", + "qalhAaJoQ7AN", + "Jg7clqogFOyD", + "5gBYmUqiupBl" + ], + "title": "Differences from upstream", + "notePosition": 20, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "lY19SLxUMj3J", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "fullContentWidth", + "value": "", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "differences-from-upstream", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Differences from upstream.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "lY19SLxUMj3J", + "notePath": [ + "jdjRLhLV3TtI", + "qalhAaJoQ7AN", + "Jg7clqogFOyD", + "lY19SLxUMj3J" + ], + "title": "ckeditor5-math", + "notePosition": 30, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "ckeditor5-math", + "isInheritable": false, + "position": 40 + } + ], + "format": "markdown", + "dataFileName": "ckeditor5-math.md", + "attachments": [ + { + "attachmentId": "UlSZYhYX8Kfj", + "title": "image.png", + "role": "image", + "mime": "image/png", + "position": 10, + "dataFileName": "ckeditor5-math_image.png" + } + ] + } + ] + } + ] + }, { "isClone": false, "noteId": "yeqU0zo0ZQ83", @@ -443,8 +1434,8 @@ "jdjRLhLV3TtI", "yeqU0zo0ZQ83" ], - "title": "Architecture", - "notePosition": 300, + "title": "Concepts", + "notePosition": 330, "prefix": null, "isExpanded": false, "type": "text", @@ -453,14 +1444,14 @@ { "type": "label", "name": "shareAlias", - "value": "architecture", + "value": "concepts", "isInheritable": false, "position": 10 }, { "type": "label", "name": "iconClass", - "value": "bx bx-arch", + "value": "bx bx-sitemap", "isInheritable": false, "position": 20 }, @@ -474,7 +1465,7 @@ ], "format": "markdown", "attachments": [], - "dirFileName": "Architecture", + "dirFileName": "Concepts", "children": [ { "isClone": false, @@ -537,6 +1528,40 @@ "dataFileName": "Branch prefixes.md", "attachments": [] }, + { + "isClone": false, + "noteId": "6Yms5izbd0GF", + "notePath": [ + "jdjRLhLV3TtI", + "yeqU0zo0ZQ83", + "6Yms5izbd0GF" + ], + "title": "Cache", + "notePosition": 30, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "iconClass", + "value": "bx bx-microchip", + "isInheritable": false, + "position": 20 + }, + { + "type": "label", + "name": "shareAlias", + "value": "cache", + "isInheritable": false, + "position": 30 + } + ], + "format": "markdown", + "dataFileName": "Cache.md", + "attachments": [] + }, { "isClone": false, "noteId": "oqg9OpK8xfcm", @@ -546,7 +1571,7 @@ "oqg9OpK8xfcm" ], "title": "CI", - "notePosition": 30, + "notePosition": 40, "prefix": null, "isExpanded": false, "type": "text", @@ -618,511 +1643,6 @@ } ] }, - { - "isClone": false, - "noteId": "vNMojjUN76jc", - "notePath": [ - "jdjRLhLV3TtI", - "yeqU0zo0ZQ83", - "vNMojjUN76jc" - ], - "title": "Database structure", - "notePosition": 40, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "database", - "isInheritable": false, - "position": 20 - }, - { - "type": "label", - "name": "iconClass", - "value": "bx bx-data", - "isInheritable": false, - "position": 30 - } - ], - "format": "markdown", - "attachments": [], - "dirFileName": "Database structure", - "children": [ - { - "isClone": false, - "noteId": "e6GnYOXeIWjg", - "notePath": [ - "jdjRLhLV3TtI", - "yeqU0zo0ZQ83", - "vNMojjUN76jc", - "e6GnYOXeIWjg" - ], - "title": "attachments", - "notePosition": 20, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "DSkl8C325tEC", - "isInheritable": false, - "position": 10 - }, - { - "type": "relation", - "name": "internalLink", - "value": "UvXpeSqfYc6d", - "isInheritable": false, - "position": 20 - }, - { - "type": "relation", - "name": "internalLink", - "value": "VIcWnKGs0sMh", - "isInheritable": false, - "position": 30 - }, - { - "type": "relation", - "name": "internalLink", - "value": "tM3rIZQzlum4", - "isInheritable": false, - "position": 40 - }, - { - "type": "label", - "name": "iconClass", - "value": "bx bx-table", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "attachments", - "isInheritable": false, - "position": 50 - } - ], - "format": "markdown", - "dataFileName": "attachments.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "ciL84vNBNi9y", - "notePath": [ - "jdjRLhLV3TtI", - "yeqU0zo0ZQ83", - "vNMojjUN76jc", - "ciL84vNBNi9y" - ], - "title": "attributes", - "notePosition": 30, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "DSkl8C325tEC", - "isInheritable": false, - "position": 20 - }, - { - "type": "relation", - "name": "internalLink", - "value": "tM3rIZQzlum4", - "isInheritable": false, - "position": 30 - }, - { - "type": "label", - "name": "iconClass", - "value": "bx bx-table", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "attributes", - "isInheritable": false, - "position": 40 - } - ], - "format": "markdown", - "dataFileName": "attributes.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "VIcWnKGs0sMh", - "notePath": [ - "jdjRLhLV3TtI", - "yeqU0zo0ZQ83", - "vNMojjUN76jc", - "VIcWnKGs0sMh" - ], - "title": "blobs", - "notePosition": 40, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "iconClass", - "value": "bx bx-table", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "blobs", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "blobs.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "GskLPkgY5n6E", - "notePath": [ - "jdjRLhLV3TtI", - "yeqU0zo0ZQ83", - "vNMojjUN76jc", - "GskLPkgY5n6E" - ], - "title": "branches", - "notePosition": 50, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "h8AsuFjSD4fB", - "isInheritable": false, - "position": 10 - }, - { - "type": "relation", - "name": "internalLink", - "value": "DSkl8C325tEC", - "isInheritable": false, - "position": 20 - }, - { - "type": "relation", - "name": "internalLink", - "value": "tM3rIZQzlum4", - "isInheritable": false, - "position": 30 - }, - { - "type": "label", - "name": "iconClass", - "value": "bx bx-table", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "branches", - "isInheritable": false, - "position": 40 - } - ], - "format": "markdown", - "dataFileName": "branches.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "ohhExR078MPU", - "notePath": [ - "jdjRLhLV3TtI", - "yeqU0zo0ZQ83", - "vNMojjUN76jc", - "ohhExR078MPU" - ], - "title": "entity_changes", - "notePosition": 51, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "iconClass", - "value": "bx bx-table", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "entity-changes", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "entity_changes.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "bRqbIg633nCs", - "notePath": [ - "jdjRLhLV3TtI", - "yeqU0zo0ZQ83", - "vNMojjUN76jc", - "bRqbIg633nCs" - ], - "title": "etapi_tokens", - "notePosition": 52, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "tM3rIZQzlum4", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "iconClass", - "value": "bx bx-table", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "etapi-tokens", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "etapi_tokens.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "DSkl8C325tEC", - "notePath": [ - "jdjRLhLV3TtI", - "yeqU0zo0ZQ83", - "vNMojjUN76jc", - "DSkl8C325tEC" - ], - "title": "notes", - "notePosition": 53, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "VIcWnKGs0sMh", - "isInheritable": false, - "position": 10 - }, - { - "type": "relation", - "name": "internalLink", - "value": "UvXpeSqfYc6d", - "isInheritable": false, - "position": 20 - }, - { - "type": "relation", - "name": "internalLink", - "value": "tM3rIZQzlum4", - "isInheritable": false, - "position": 30 - }, - { - "type": "label", - "name": "iconClass", - "value": "bx bx-table", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "notes", - "isInheritable": false, - "position": 40 - } - ], - "format": "markdown", - "dataFileName": "notes.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "4oeftEmy77Bt", - "notePath": [ - "jdjRLhLV3TtI", - "yeqU0zo0ZQ83", - "vNMojjUN76jc", - "4oeftEmy77Bt" - ], - "title": "options", - "notePosition": 54, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "iconClass", - "value": "bx bx-table", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "options", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "options.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "VyFirdgAOoh5", - "notePath": [ - "jdjRLhLV3TtI", - "yeqU0zo0ZQ83", - "vNMojjUN76jc", - "VyFirdgAOoh5" - ], - "title": "recent_notes", - "notePosition": 55, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "DSkl8C325tEC", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "iconClass", - "value": "bx bx-table", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "recent-notes", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "recent_notes.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "s7ZBiaJVNumK", - "notePath": [ - "jdjRLhLV3TtI", - "yeqU0zo0ZQ83", - "vNMojjUN76jc", - "s7ZBiaJVNumK" - ], - "title": "revisions", - "notePosition": 56, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "iconClass", - "value": "bx bx-table", - "isInheritable": false, - "position": 10 - }, - { - "type": "relation", - "name": "internalLink", - "value": "DSkl8C325tEC", - "isInheritable": false, - "position": 20 - }, - { - "type": "relation", - "name": "internalLink", - "value": "UvXpeSqfYc6d", - "isInheritable": false, - "position": 30 - }, - { - "type": "relation", - "name": "internalLink", - "value": "VIcWnKGs0sMh", - "isInheritable": false, - "position": 40 - }, - { - "type": "label", - "name": "shareAlias", - "value": "revisions", - "isInheritable": false, - "position": 50 - } - ], - "format": "markdown", - "dataFileName": "revisions.md", - "attachments": [] - } - ] - }, { "isClone": false, "noteId": "tM3rIZQzlum4", @@ -1191,6 +1711,40 @@ "dataFileName": "Demo document.md", "attachments": [] }, + { + "isClone": false, + "noteId": "TiUll0Osoaz6", + "notePath": [ + "jdjRLhLV3TtI", + "yeqU0zo0ZQ83", + "TiUll0Osoaz6" + ], + "title": "Entities", + "notePosition": 70, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "entities", + "isInheritable": false, + "position": 20 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bxs-note", + "isInheritable": false, + "position": 30 + } + ], + "format": "markdown", + "dataFileName": "Entities.md", + "attachments": [] + }, { "isClone": false, "noteId": "UzRirf46Xi46", @@ -1200,7 +1754,7 @@ "UzRirf46Xi46" ], "title": "Hidden notes", - "notePosition": 70, + "notePosition": 80, "prefix": null, "isExpanded": false, "type": "text", @@ -1234,7 +1788,7 @@ "m2W35hwSDUeh" ], "title": "Icons", - "notePosition": 80, + "notePosition": 90, "prefix": null, "isExpanded": false, "type": "text", @@ -1275,7 +1829,7 @@ "TLXJwBDo8Rdv" ], "title": "Internationalisation / Translations", - "notePosition": 90, + "notePosition": 100, "prefix": null, "isExpanded": false, "type": "text", @@ -1410,7 +1964,7 @@ "Usiyzn9C4WFv" ], "title": "Launchers", - "notePosition": 100, + "notePosition": 110, "prefix": null, "isExpanded": false, "type": "text", @@ -1437,7 +1991,7 @@ "qjQNyaYXSNWu" ], "title": "Note Revisions", - "notePosition": 110, + "notePosition": 120, "prefix": null, "isExpanded": false, "type": "text", @@ -1471,12 +2025,20 @@ "7RBJMqVz2EsJ" ], "title": "Note Types", - "notePosition": 120, + "notePosition": 130, "prefix": null, "isExpanded": false, "type": "text", "mime": "text/html", - "attributes": [], + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "note-types", + "isInheritable": false, + "position": 20 + } + ], "format": "markdown", "attachments": [], "dirFileName": "Note Types", @@ -1805,7 +2367,7 @@ "6dC7ha5vjqqS" ], "title": "Options", - "notePosition": 130, + "notePosition": 140, "prefix": null, "isExpanded": false, "type": "text", @@ -1870,12 +2432,19 @@ "W0msUwLxm40d" ], "title": "Printing and exporting to PDF", - "notePosition": 140, + "notePosition": 150, "prefix": null, "isExpanded": false, "type": "text", "mime": "text/html", "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "k7RavjuXQt8z", + "isInheritable": false, + "position": 20 + }, { "type": "label", "name": "shareAlias", @@ -1883,13 +2452,6 @@ "isInheritable": false, "position": 20 }, - { - "type": "relation", - "name": "internalLink", - "value": "k7RavjuXQt8z", - "isInheritable": false, - "position": 40 - }, { "type": "label", "name": "iconClass", @@ -1911,7 +2473,7 @@ "UvXpeSqfYc6d" ], "title": "Protected entities", - "notePosition": 150, + "notePosition": 160, "prefix": null, "isExpanded": false, "type": "text", @@ -1966,7 +2528,7 @@ "vphziLmQeQHY" ], "title": "Share", - "notePosition": 160, + "notePosition": 170, "prefix": null, "isExpanded": false, "type": "text", @@ -2000,7 +2562,7 @@ "n9wYW9nUTynV" ], "title": "Synchronisation", - "notePosition": 170, + "notePosition": 180, "prefix": null, "isExpanded": false, "type": "text", @@ -2022,6 +2584,7 @@ } ], "format": "markdown", + "dataFileName": "Synchronisation.md", "attachments": [], "dirFileName": "Synchronisation", "children": [ @@ -2064,7 +2627,7 @@ "k7RavjuXQt8z" ], "title": "Syntax highlighting", - "notePosition": 180, + "notePosition": 190, "prefix": null, "isExpanded": false, "type": "text", @@ -2098,7 +2661,7 @@ "7BCukQTCm7fv" ], "title": "Themes", - "notePosition": 190, + "notePosition": 200, "prefix": null, "isExpanded": false, "type": "text", @@ -2133,7 +2696,7 @@ "YjerxU7Aii8X" ], "title": "Troubleshooting", - "notePosition": 340, + "notePosition": 370, "prefix": null, "isExpanded": false, "type": "text", @@ -2184,44 +2747,16 @@ "format": "markdown", "dataFileName": "better-sqlite3 was compiled ag.md", "attachments": [] - } - ] - }, - { - "isClone": false, - "noteId": "ibAPHul7Efvr", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr" - ], - "title": "Old documentation", - "notePosition": 350, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "old-documentation", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "attachments": [], - "dirFileName": "Old documentation", - "children": [ + }, { "isClone": false, - "noteId": "rLWcPPQi7Eso", + "noteId": "QUb0fRhbpT8E", "notePath": [ "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "rLWcPPQi7Eso" + "YjerxU7Aii8X", + "QUb0fRhbpT8E" ], - "title": "Releasing a version", + "title": "Error [TransformError]: The package \"@esbuild/linux-x64\" could not be found, and is needed by esbuild.", "notePosition": 20, "prefix": null, "isExpanded": false, @@ -2231,25 +2766,95 @@ { "type": "label", "name": "shareAlias", - "value": "releasing", + "value": "esbuild-error", "isInheritable": false, "position": 20 } ], "format": "markdown", - "dataFileName": "Releasing a version.md", + "dataFileName": "Error [TransformError] The pac.md", + "attachments": [] + } + ] + }, + { + "isClone": false, + "noteId": "dtKC3FmoWOrv", + "notePath": [ + "jdjRLhLV3TtI", + "dtKC3FmoWOrv" + ], + "title": "Testing", + "notePosition": 390, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "w6gMvKh0UAVT", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "shareAlias", + "value": "testing", + "isInheritable": false, + "position": 20 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bxs-eyedropper", + "isInheritable": false, + "position": 30 + } + ], + "format": "markdown", + "dataFileName": "Testing.md", + "attachments": [], + "dirFileName": "Testing", + "children": [ + { + "isClone": false, + "noteId": "ETeT5YO61DAW", + "notePath": [ + "jdjRLhLV3TtI", + "dtKC3FmoWOrv", + "ETeT5YO61DAW" + ], + "title": "Unit tests", + "notePosition": 10, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "unit-tests", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Unit tests.md", "attachments": [] }, { "isClone": false, - "noteId": "6BWwXzPCph4G", + "noteId": "C5MUQczZ5R9N", "notePath": [ "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "6BWwXzPCph4G" + "dtKC3FmoWOrv", + "C5MUQczZ5R9N" ], - "title": "Project maintenance", - "notePosition": 60, + "title": "Integration testing", + "notePosition": 20, "prefix": null, "isExpanded": false, "type": "text", @@ -2258,101 +2863,25 @@ { "type": "label", "name": "shareAlias", - "value": "project-maintenance", + "value": "integration", "isInheritable": false, "position": 20 } ], "format": "markdown", - "attachments": [], - "dirFileName": "Project maintenance", - "children": [ - { - "isClone": false, - "noteId": "fa6hAJ9Ith3A", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "6BWwXzPCph4G", - "fa6hAJ9Ith3A" - ], - "title": "Updating dependencies", - "notePosition": 10, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "Xfi1ScuBTKJf", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "updating-deps", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Updating dependencies.md", - "attachments": [], - "dirFileName": "Updating dependencies", - "children": [ - { - "isClone": false, - "noteId": "Xfi1ScuBTKJf", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "6BWwXzPCph4G", - "fa6hAJ9Ith3A", - "Xfi1ScuBTKJf" - ], - "title": "bettersqlite binaries", - "notePosition": 10, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "PXzm2t3sCdsP", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "bettersqlite-binaries", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "bettersqlite binaries.md", - "attachments": [] - } - ] - } - ] + "dataFileName": "Integration testing.md", + "attachments": [] }, { "isClone": false, - "noteId": "re0QTuqiYnVb", + "noteId": "bIfKwfCnqpeI", "notePath": [ "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "re0QTuqiYnVb" + "dtKC3FmoWOrv", + "bIfKwfCnqpeI" ], - "title": "Scripting", - "notePosition": 80, + "title": "Test database", + "notePosition": 30, "prefix": null, "isExpanded": false, "type": "text", @@ -2361,144 +2890,25 @@ { "type": "label", "name": "shareAlias", - "value": "scripting", + "value": "test-database", "isInheritable": false, "position": 20 } ], "format": "markdown", - "attachments": [], - "dirFileName": "Scripting", - "children": [ - { - "isClone": false, - "noteId": "gz6zq5rlHqMa", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "re0QTuqiYnVb", - "gz6zq5rlHqMa" - ], - "title": "Widgets", - "notePosition": 10, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "widgets", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Widgets.md", - "attachments": [], - "dirFileName": "Widgets", - "children": [ - { - "isClone": false, - "noteId": "M8IppdwVHSjG", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "re0QTuqiYnVb", - "gz6zq5rlHqMa", - "M8IppdwVHSjG" - ], - "title": "Right pane widget", - "notePosition": 10, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "right-pane-widget", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Right pane widget.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "VqGQnnPGnqAU", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "re0QTuqiYnVb", - "gz6zq5rlHqMa", - "VqGQnnPGnqAU" - ], - "title": "CSS", - "notePosition": 20, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "css", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "CSS.md", - "attachments": [] - } - ] - }, - { - "isClone": false, - "noteId": "fZ2IGYFXjkEy", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "re0QTuqiYnVb", - "fZ2IGYFXjkEy" - ], - "title": "Server-side imports", - "notePosition": 20, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "server-imports", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Server-side imports.md", - "attachments": [] - } - ] + "dataFileName": "Test database.md", + "attachments": [] }, { "isClone": false, - "noteId": "Sow7ThJozkzJ", + "noteId": "w6gMvKh0UAVT", "notePath": [ "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "Sow7ThJozkzJ" + "dtKC3FmoWOrv", + "w6gMvKh0UAVT" ], - "title": "Documentation", - "notePosition": 90, + "title": "End-to-end tests", + "notePosition": 40, "prefix": null, "isExpanded": false, "type": "text", @@ -2507,718 +2917,14 @@ { "type": "label", "name": "shareAlias", - "value": "documentation", + "value": "running-tests", "isInheritable": false, "position": 20 } ], "format": "markdown", - "dataFileName": "Documentation.md", - "attachments": [ - { - "attachmentId": "2bUrJyt2yfsd", - "title": "image.png", - "role": "image", - "mime": "image/png", - "position": 10, - "dataFileName": "Documentation_image.png" - } - ], - "dirFileName": "Documentation", - "children": [ - { - "isClone": false, - "noteId": "LjqM0VUL1CrU", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "Sow7ThJozkzJ", - "LjqM0VUL1CrU" - ], - "title": "Documentation references in the application", - "notePosition": 10, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "doc-references", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Documentation references in th.md", - "attachments": [] - } - ] - }, - { - "isClone": false, - "noteId": "dtKC3FmoWOrv", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dtKC3FmoWOrv" - ], - "title": "Testing", - "notePosition": 100, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "testing", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Testing.md", - "attachments": [], - "dirFileName": "Testing", - "children": [ - { - "isClone": false, - "noteId": "C5MUQczZ5R9N", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dtKC3FmoWOrv", - "C5MUQczZ5R9N" - ], - "title": "Integration testing", - "notePosition": 10, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "integration", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "attachments": [], - "dirFileName": "Integration testing", - "children": [ - { - "isClone": false, - "noteId": "pH4RsxqifVpK", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dtKC3FmoWOrv", - "C5MUQczZ5R9N", - "pH4RsxqifVpK" - ], - "title": "Setting up authentication", - "notePosition": 20, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "auth", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Setting up authentication.md", - "attachments": [ - { - "attachmentId": "aWFXFuXNon7J", - "title": "image.png", - "role": "image", - "mime": "image/png", - "position": 10, - "dataFileName": "Setting up authentication_.png" - }, - { - "attachmentId": "JRbtB4byzewo", - "title": "image.png", - "role": "image", - "mime": "image/png", - "position": 10, - "dataFileName": "1_Setting up authentication_.png" - } - ] - }, - { - "isClone": false, - "noteId": "bIfKwfCnqpeI", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dtKC3FmoWOrv", - "C5MUQczZ5R9N", - "bIfKwfCnqpeI" - ], - "title": "Test database", - "notePosition": 30, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "test-database", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Test database.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "w6gMvKh0UAVT", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dtKC3FmoWOrv", - "C5MUQczZ5R9N", - "w6gMvKh0UAVT" - ], - "title": "Running tests", - "notePosition": 40, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "running-tests", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Running tests.md", - "attachments": [] - } - ] - } - ] - }, - { - "isClone": false, - "noteId": "dHfw0XZE515z", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dHfw0XZE515z" - ], - "title": "Sub-projects", - "notePosition": 110, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "subprojects", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "attachments": [], - "dirFileName": "Sub-projects", - "children": [ - { - "isClone": false, - "noteId": "JkTy2zz8Zbyq", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dHfw0XZE515z", - "JkTy2zz8Zbyq" - ], - "title": "CKEditor", - "notePosition": 20, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "ckeditor", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "attachments": [], - "dirFileName": "CKEditor", - "children": [ - { - "isClone": false, - "noteId": "5yWZVlKPjLCC", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dHfw0XZE515z", - "JkTy2zz8Zbyq", - "5yWZVlKPjLCC" - ], - "title": "Environment setup", - "notePosition": 10, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "CaInsmrlZhR6", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "environment-setup", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Environment setup.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "CaInsmrlZhR6", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dHfw0XZE515z", - "JkTy2zz8Zbyq", - "CaInsmrlZhR6" - ], - "title": "Building the editor", - "notePosition": 20, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "5yWZVlKPjLCC", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "building-the-editor", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Building the editor.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "5gBYmUqiupBl", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dHfw0XZE515z", - "JkTy2zz8Zbyq", - "5gBYmUqiupBl" - ], - "title": "Differences from upstream", - "notePosition": 30, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "lY19SLxUMj3J", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "fullContentWidth", - "value": "", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "differences-from-upstream", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Differences from upstream.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "Q9FyKVERd1Lb", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dHfw0XZE515z", - "JkTy2zz8Zbyq", - "Q9FyKVERd1Lb" - ], - "title": "Updating to a newer version of CKEditor", - "notePosition": 40, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "5yWZVlKPjLCC", - "isInheritable": false, - "position": 10 - }, - { - "type": "relation", - "name": "internalLink", - "value": "CaInsmrlZhR6", - "isInheritable": false, - "position": 20 - }, - { - "type": "relation", - "name": "internalLink", - "value": "yAFSS6awVbaZ", - "isInheritable": false, - "position": 30 - }, - { - "type": "label", - "name": "shareAlias", - "value": "updating", - "isInheritable": false, - "position": 40 - } - ], - "format": "markdown", - "dataFileName": "Updating to a newer version of.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "yAFSS6awVbaZ", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dHfw0XZE515z", - "JkTy2zz8Zbyq", - "yAFSS6awVbaZ" - ], - "title": "Versions and external plugins", - "notePosition": 50, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "lY19SLxUMj3J", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "external-plugin-and-versions", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Versions and external plugins.md", - "attachments": [] - } - ] - }, - { - "isClone": false, - "noteId": "lY19SLxUMj3J", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dHfw0XZE515z", - "lY19SLxUMj3J" - ], - "title": "ckeditor5-math", - "notePosition": 30, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "JkTy2zz8Zbyq", - "isInheritable": false, - "position": 10 - }, - { - "type": "relation", - "name": "internalLink", - "value": "UMN2ABrBU5D7", - "isInheritable": false, - "position": 20 - }, - { - "type": "relation", - "name": "internalLink", - "value": "CaInsmrlZhR6", - "isInheritable": false, - "position": 30 - }, - { - "type": "label", - "name": "shareAlias", - "value": "ckeditor5-math", - "isInheritable": false, - "position": 40 - } - ], - "format": "markdown", - "dataFileName": "ckeditor5-math.md", - "attachments": [ - { - "attachmentId": "UlSZYhYX8Kfj", - "title": "image.png", - "role": "image", - "mime": "image/png", - "position": 10, - "dataFileName": "ckeditor5-math_image.png" - } - ], - "dirFileName": "ckeditor5-math", - "children": [ - { - "isClone": false, - "noteId": "vpbbBaypScLb", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dHfw0XZE515z", - "lY19SLxUMj3J", - "vpbbBaypScLb" - ], - "title": "Updating with upstream", - "notePosition": 10, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "UMN2ABrBU5D7", - "isInheritable": false, - "position": 10 - }, - { - "type": "label", - "name": "shareAlias", - "value": "updating-upstream", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Updating with upstream.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "UMN2ABrBU5D7", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "dHfw0XZE515z", - "lY19SLxUMj3J", - "UMN2ABrBU5D7" - ], - "title": "Release management & continuous integration", - "notePosition": 20, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "release-management", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Release management & continuou.md", - "attachments": [] - } - ] - } - ] - }, - { - "isClone": false, - "noteId": "QRLbiDXNxoWN", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "QRLbiDXNxoWN" - ], - "title": "Troubleshooting", - "notePosition": 120, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "troubleshooting", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "attachments": [], - "dirFileName": "Troubleshooting", - "children": [ - { - "isClone": false, - "noteId": "QUb0fRhbpT8E", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "QRLbiDXNxoWN", - "QUb0fRhbpT8E" - ], - "title": "Error [TransformError]: The package \"@esbuild/linux-x64\" could not be found, and is needed by esbuild.", - "notePosition": 10, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "esbuild-error", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Error [TransformError] The pac.md", - "attachments": [] - } - ] - }, - { - "isClone": false, - "noteId": "x6lgrdztQwVB", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "x6lgrdztQwVB" - ], - "title": "Installation", - "notePosition": 130, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "installation", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "attachments": [], - "dirFileName": "Installation", - "children": [ - { - "isClone": false, - "noteId": "bOjeTrUViwLw", - "notePath": [ - "jdjRLhLV3TtI", - "ibAPHul7Efvr", - "x6lgrdztQwVB", - "bOjeTrUViwLw" - ], - "title": "Download latest nightly and install it", - "notePosition": 10, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "download-nightly", - "isInheritable": false, - "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Download latest nightly and in.md", - "attachments": [] - } - ] + "dataFileName": "End-to-end tests.md", + "attachments": [] } ] } diff --git a/docs/Developer Guide/Developer Guide.md b/docs/Developer Guide/Developer Guide.md index 2dd9f42de..8f5721b30 100644 --- a/docs/Developer Guide/Developer Guide.md +++ b/docs/Developer Guide/Developer Guide.md @@ -1,4 +1,15 @@ # Developer Guide This documentation is intended for developers planning to implement new features or maintain the Trilium Notes application, as it describes the architecture of the application. -For the user-facing documentation, including how to write scripts and the various APIs, consult the [user guide](https://docs.triliumnotes.org/user-guide/) instead. \ No newline at end of file +For the user-facing documentation, including how to write scripts and the various APIs, consult the [user guide](https://docs.triliumnotes.org/user-guide/) instead. + +### Quick links + +* Environment Setup +* Project Structure + +### External links + +* The [Trilium Notes website](https://triliumnotes.org/), for a quick presentation of the application. +* [User Guide](https://docs.triliumnotes.org/user-guide/), to understand the concepts of the application itself. +* [GitHub Repository (TriliumNext/Trilium)](https://github.com/TriliumNext/Trilium/) \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture.md b/docs/Developer Guide/Developer Guide/Architecture.md new file mode 100644 index 000000000..66cb82eea --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Architecture.md @@ -0,0 +1,202 @@ +# Architecture +Trilium Notes is a hierarchical note-taking application built as a TypeScript monorepo. It supports multiple deployment modes (desktop, server, mobile web) and features advanced capabilities including synchronization, scripting, encryption, and rich content editing. + +### Key Characteristics + +* **Monorepo Architecture**: Uses pnpm workspaces for dependency management +* **Multi-Platform**: Desktop (Electron), Server (Node.js/Express), and Mobile Web +* **TypeScript-First**: Strong typing throughout the codebase +* **Plugin-Based**: Extensible architecture for note types and UI components +* **Offline-First**: Full functionality without network connectivity +* **Synchronization-Ready**: Built-in sync protocol for multi-device usage + +### Technology Stack + +* **Runtime**: Node.js (backend), Browser/Electron (frontend) +* **Language**: TypeScript, JavaScript +* **Database**: SQLite (better-sqlite3) +* **Build Tools**: + * Client: Vite, + * Server: ESBuild (bundling) + * Package manager: pnpm +* **UI Framework**: Custom widget-based system (vanilla HTML, CSS & JavaScript + jQuery), in the process of converting to React/Preact. +* **Rich Text**: CKEditor 5 (customized) +* **Code Editing**: CodeMirror 6 +* **Desktop**: Electron +* **Server**: Express.js + +## Main architecture + +Trilium follows a **client-server architecture** even in desktop mode, where Electron runs both the backend server and frontend client within the same process. + +``` +graph TB + subgraph Frontend + Widgets[Widgets
    System] + Froca[Froca
    Cache] + UIServices[UI
    Services] + end + + subgraph Backend["Backend Server"] + Express[Express
    Routes] + Becca[Becca
    Cache] + ScriptEngine[Script
    Engine] + Database[(SQLite
    Database)] + end + + Widgets -.-> API[WebSocket & REST API] + Froca -.-> API + UIServices -.-> API + API -.-> Express + API -.-> Becca + API -.-> ScriptEngine + Becca --> Database + Express --> Database + ScriptEngine --> Database +``` + +### Deployment Modes + +1. **Desktop Application** + * Electron wrapper running both frontend and backend + * Local SQLite database + * Full offline functionality + * Cross-platform (Windows, macOS, Linux) +2. **Server Installation** + * Node.js server exposing web interface + * Multi-user capable + * Can sync with desktop clients + * Docker deployment supported +3. **Mobile Web** + * Optimized responsive interface + * Accessed via browser + * Requires server installation + +## Monorepo Structure + +Trilium uses **pnpm workspaces** to manage its monorepo structure, with apps and packages clearly separated. + +``` +trilium/ +├── apps/ # Runnable applications +│ ├── client/ # Frontend application (shared by server & desktop) +│ ├── server/ # Node.js server with web interface +│ ├── desktop/ # Electron desktop application +│ ├── web-clipper/ # Browser extension for web content capture +│ ├── db-compare/ # Database comparison tool +│ ├── dump-db/ # Database export tool +│ ├── edit-docs/ # Documentation editing tool +│ ├── build-docs/ # Documentation build tool +│ └── website/ # Marketing website +│ +├── packages/ # Shared libraries +│ ├── commons/ # Shared interfaces and utilities +│ ├── ckeditor5/ # Custom rich text editor +│ ├── codemirror/ # Code editor customizations +│ ├── highlightjs/ # Syntax highlighting +│ ├── ckeditor5-admonition/ # CKEditor plugin: admonitions +│ ├── ckeditor5-footnotes/ # CKEditor plugin: footnotes +│ ├── ckeditor5-keyboard-marker/# CKEditor plugin: keyboard shortcuts +│ ├── ckeditor5-math/ # CKEditor plugin: math equations +│ ├── ckeditor5-mermaid/ # CKEditor plugin: diagrams +│ ├── express-partial-content/ # HTTP partial content middleware +│ ├── share-theme/ # Shared note theme +│ ├── splitjs/ # Split pane library +│ └── turndown-plugin-gfm/ # Markdown conversion +│ +├── docs/ # Documentation +├── scripts/ # Build and utility scripts +└── patches/ # Package patches (via pnpm) +``` + +### Package Dependencies + +The monorepo uses workspace protocol (`workspace:*`) for internal dependencies: + +``` +desktop → client → commons +server → client → commons +client → ckeditor5, codemirror, highlightjs +ckeditor5 → ckeditor5-* plugins +``` + +## Security summary + +### Encryption System + +**Per-Note Encryption:** + +* Notes can be individually protected +* AES-128-CBC encryption for encrypted notes. +* Separate protected session management + +**Protected Session:** + +* Time-limited access to protected notes +* Automatic timeout +* Re-authentication required +* Frontend: `protected_session.ts` +* Backend: `protected_session.ts` + +### Authentication + +**Password Auth:** + +* PBKDF2 key derivation +* Salt per installation +* Hash verification + +**OpenID Connect:** + +* External identity provider support +* OAuth 2.0 flow +* Configurable providers + +**TOTP (2FA):** + +* Time-based one-time passwords +* QR code setup +* Backup codes + +### Authorization + +**Single-User Model:** + +* Desktop: single user (owner) +* Server: single user per installation + +**Share Notes:** + +* Public access without authentication +* Separate Shaca cache +* Read-only access + +### CSRF Protection + +**CSRF Tokens:** + +* Required for state-changing operations +* Token in header or cookie +* Validation middleware + +### Input Sanitization + +**XSS Prevention:** + +* DOMPurify for HTML sanitization +* CKEditor content filtering +* CSP headers + +**SQL Injection:** + +* Parameterized queries only +* Better-sqlite3 prepared statements +* No string concatenation in SQL + +### Dependency Security + +**Vulnerability Scanning:** + +* Renovate bot for updates +* npm audit integration +* Override vulnerable sub-dependencies \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/APIs.md b/docs/Developer Guide/Developer Guide/Architecture/APIs.md new file mode 100644 index 000000000..cdd954a61 --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Architecture/APIs.md @@ -0,0 +1,72 @@ +# APIs +### Internal API + +**REST Endpoints** (`/api/*`) + +Used by the frontend for all operations: + +**Note Operations:** + +* `GET /api/notes/:noteId` - Get note +* `POST /api/notes/:noteId/content` - Update content +* `PUT /api/notes/:noteId` - Update metadata +* `DELETE /api/notes/:noteId` - Delete note + +**Tree Operations:** + +* `GET /api/tree` - Get note tree +* `POST /api/branches` - Create branch +* `PUT /api/branches/:branchId` - Update branch +* `DELETE /api/branches/:branchId` - Delete branch + +**Search:** + +* `GET /api/search?query=...` - Search notes +* `GET /api/search-note/:noteId` - Execute search note + +### ETAPI (External API) + +Located at: `apps/server/src/etapi/` + +**Purpose:** Third-party integrations and automation + +**Authentication:** Token-based (ETAPI tokens) + +**OpenAPI Spec:** Auto-generated + +**Key Endpoints:** + +* `/etapi/notes` - Note CRUD +* `/etapi/branches` - Branch management +* `/etapi/attributes` - Attribute operations +* `/etapi/attachments` - Attachment handling + +**Example:** + +``` +curl -H "Authorization: YOUR_TOKEN" \ + https://trilium.example.com/etapi/notes/noteId +``` + +### WebSocket API + +Located at: `apps/server/src/services/ws.ts` + +**Purpose:** Real-time updates and synchronization + +**Protocol:** WebSocket (Socket.IO-like custom protocol) + +**Message Types:** + +* `sync` - Synchronization request +* `entity-change` - Entity update notification +* `refresh-tree` - Tree structure changed +* `open-note` - Open note in UI + +**Client Subscribe:** + +```typescript +ws.subscribe('entity-change', (data) => { + froca.processEntityChange(data) +}) +``` \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Arhitecture Decision Records.md b/docs/Developer Guide/Developer Guide/Architecture/Arhitecture Decision Records.md new file mode 100644 index 000000000..c524642cd --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Architecture/Arhitecture Decision Records.md @@ -0,0 +1,62 @@ +# Arhitecture Decision Records +## 🚀 Future milestones + +* [Mobile](https://github.com/TriliumNext/Trilium/issues/7447) +* [Multi-user](https://github.com/TriliumNext/Trilium/issues/4956) + +## Aug 2025 - present: Port the client to React + +- [x] [Type widgets](https://github.com/TriliumNext/Trilium/pull/7044) +- [x] [Collections](https://github.com/TriliumNext/Trilium/pull/6837) +- [x] [Various widgets](https://github.com/TriliumNext/Trilium/pull/6830) +- [x] [Floating buttons](https://github.com/TriliumNext/Trilium/pull/6811) +- [x] [Settings](https://github.com/TriliumNext/Trilium/pull/6660) + +## Aug 2025 - Move away from NX + +We took the decision of moving away from the NX monorepo tool, due to: + +* Various issues with the cache, especially after an update of the NX dependencies which required periodical `nx reset` to get rid of. +* Various issues with memory and CPU consumption along the way, due to the NX daemon (including it remaining as a background process after closing the IDE). +* On Windows, almost always there was a freeze on every second build. +* Various hacks that were needed to achieve what we needed (especially for artifacts since NX would not copy assets if they were in `.gitignore` for some arbitrary reason and requiring a patch that made it difficult to maintain across updates). + +As a result, we decided to switch to… nothing. Why? + +* `pnpm` (which we were already using) covers the basic needs of a monorepo via workspaces on its own. +* Our client-side solution, Vite already supports navigating through projects without requiring built artifacts. This makes the build process slightly faster (especially cold starts) at a slighter bigger RAM consumption. +* ESBuild, on the server-side, also seems happy to go across projects without an issue. + +Apart from this: + +* In dev mode, the server now runs directly using `tsx` and not built and then run. This means that it'll run much faster. +* We're back to an architecture where the `server` and the `desktop` host their own Vite instance as a middleware. What this means that there is no `client:dev` and no separate port to handle. + * This makes it possible to easily test on mobile in dev mode, since there's a single port to access. + * The downside is that the initial start up time is longer while Vite is spinning up. Nevertheless, it's still slightly faster than it used to be anyway. +* No more asset copying, which should also improve performance. +* No more messing around with the native dependency of `better-sqlite3` that caused those dreaded mismatches when running between server and desktop. We have (hopefully) found a permanent solution for it that involves no user input. +* A decent solution was put in place to allow easier development on NixOS for the desktop application. +* The desktop version has also gained back the ability to automatically refresh the client when a change is made, including live changes for React components. + +Migration steps, as a developer: + +1. In VS Code, uninstall the NX Console unless you plan to use it for other projects. +2. Remove `.nx` at project level. +3. It's ideal to clean up all your `node_modules` in the project (do note that it's not just the top-level one, but also in `apps/client`, `apps/server`, `apps/desktop`, etc.). +4. Run a `pnpm i` to set up the new dependencies and the installation +5. Instead of `nx run server:serve`, now you can simply run `pnpm dev` while in `apps/server`, or `pnpm server:start` while in the root. +6. When first starting the server, it will take slightly longer than usual to see something on the screen since the dependencies are being rebuilt. Those are later cached so subsequent runs should work better. If you end up with a white screen, simply refresh the page a few times until it shows up correctly. + +## Apr 2025: NX-based monorepo + +* Goal: Restructure the application from a mix where the client was a subfolder within the server and other dependencies such as CKEditor were scattered in various repositories to a monorepo powered by NX. +* [Initial discussion](https://github.com/TriliumNext/Trilium/issues/4941) +* [Relevant PR](https://github.com/TriliumNext/Notes/pull/1773) + +## Dec 2024: Front-end conversion to TypeScript + +* [Relevant PRs on GitHub](https://github.com/TriliumNext/Notes/pulls?q=is%3Apr+is%3Aclosed+%22Port+frontend+to+TypeScript%22) + +## Apr 2024: Back-end conversion to TypeScript + +* [Relevant PRs on GitHub](https://github.com/TriliumNext/Notes/pulls?q=is%3Apr+%22convert+backend+to+typescript%22) \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Backend.md b/docs/Developer Guide/Developer Guide/Architecture/Backend.md new file mode 100644 index 000000000..df0ddf21d --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Architecture/Backend.md @@ -0,0 +1,88 @@ +# Backend +### Application Entry Point + +Location: `apps/server/src/main.ts` + +**Startup Sequence:** + +1. Load configuration +2. Initialize database +3. Run migrations +4. Load Becca cache +5. Start Express server +6. Initialize WebSocket +7. Start scheduled tasks + +### Service Layer + +Located at: `apps/server/src/services/` + +**Core Services:** + +* **Notes Management** + * `notes.ts` - CRUD operations + * `note_contents.ts` - Content handling + * `note_types.ts` - Type-specific logic + * `cloning.ts` - Note cloning/multi-parent +* **Tree Operations** + * `tree.ts` - Tree structure management + * `branches.ts` - Branch operations + * `consistency_checks.ts` - Tree integrity +* **Search** + * `search/search.ts` - Main search engine + * `search/expressions/` - Search expression parsing + * `search/services/` - Search utilities +* **Sync** + * `sync.ts` - Synchronization protocol + * `sync_update.ts` - Update handling + * `sync_mutex.ts` - Concurrency control +* **Scripting** + * `backend_script_api.ts` - Backend script API + * `script_context.ts` - Script execution context +* **Import/Export** + * `import/` - Various import formats + * `export/` - Export to different formats + * `zip.ts` - Archive handling +* **Security** + * `encryption.ts` - Note encryption + * `protected_session.ts` - Session management + * `password.ts` - Password handling + +### Route Structure + +Located at: `apps/server/src/routes/` + +``` +routes/ +├── index.ts # Route registration +├── api/ # REST API endpoints +│ ├── notes.ts +│ ├── branches.ts +│ ├── attributes.ts +│ ├── search.ts +│ ├── login.ts +│ └── ... +└── custom/ # Special endpoints + ├── setup.ts + ├── share.ts + └── ... +``` + +**API Endpoint Pattern:** + +```typescript +router.get('/api/notes/:noteId', (req, res) => { + const noteId = req.params.noteId + const note = becca.getNote(noteId) + res.json(note.getPojoWithContent()) +}) +``` + +### Middleware + +Key middleware components: + +* `auth.ts` - Authentication +* `csrf.ts` - CSRF protection +* `request_context.ts` - Request-scoped data +* `error_handling.ts` - Error responses \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database.md b/docs/Developer Guide/Developer Guide/Architecture/Database.md new file mode 100644 index 000000000..b8836b56d --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Architecture/Database.md @@ -0,0 +1,40 @@ +# Database +Trilium uses **SQLite** (via `better-sqlite3`) as its embedded database engine, providing a reliable, file-based storage system that requires no separate database server. The database stores all notes, their relationships, metadata, and configuration. + +Schema location: `apps/server/src/assets/db/schema.sql` + +### Data Access Patterns + +**Direct SQL:** + +```typescript +// apps/server/src/services/sql.ts +sql.getRows("SELECT * FROM notes WHERE type = ?", ['text']) +sql.execute("UPDATE notes SET title = ? WHERE noteId = ?", [title, noteId]) +``` + +**Through Becca:** + +```typescript +// Recommended approach - uses cache +const note = becca.getNote('noteId') +note.title = 'New Title' +note.save() +``` + +**Through Froca (Frontend):** + +```typescript +// Read-only access +const note = froca.getNote('noteId') +console.log(note.title) +``` + +### Database Migrations + +* The migration system is in `server/src/migrations/migrations.ts` (actual definitions) and `src/services/migration.ts`. +* Both SQLite and TypeScript migrations are supported. + * Small migrations are contained directly in `src/migrations/migrations.ts`. + * Bigger TypeScript migrations are sequentially numbered (e.g., `XXXX_migration_name.ts`) and dynamically imported by `migrations.ts`. +* Automatic execution on version upgrade. +* Schema version tracked in options table. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/attachments.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attachments.md similarity index 90% rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/attachments.md rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attachments.md index 4312832dd..09ae80d4b 100644 --- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/attachments.md +++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attachments.md @@ -6,11 +6,11 @@ | `role` | Text | Non-null | | The role of the attachment: `image` for images that are attached to a note, `file` for uploaded files. | | `mime` | Text | Non-null | | The MIME type of the attachment (e.g. `image/png`) | | `title` | Text | Non-null | | The title of the attachment. | -| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../Protected%20entities.md), `0` otherwise. | +| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../../../Concepts/Protected%20entities.md), `0` otherwise. | | `position` | Integer | Non-null | 0 | Not sure where the position is relevant for attachments (saw it with values of 10 and 0). | | `blobId` | Text | Nullable | `null` | The corresponding `blobId` from the blobs table. | | `dateModified` | Text | Non-null | | Localized modification date (e.g. `2023-11-08 18:43:44.204+0200`) | | `utcDateModified` | Text | Non-null | | Modification date in UTC format (e.g. `2023-11-08 16:43:44.204Z`) | | `utcDateScheduledForErasure` | Text | Nullable | `null` | | -| `isDeleted` | Integer | Non-null | | `1` if the entity is [deleted](../Deleted%20notes.md), `0` otherwise. | +| `isDeleted` | Integer | Non-null | | `1` if the entity is [deleted](../../../Concepts/Deleted%20notes.md), `0` otherwise. | | `deleteId` | Text | Nullable | `null` | | \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/attributes.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attributes.md similarity index 84% rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/attributes.md rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attributes.md index 959073ec8..f1cbb99c4 100644 --- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/attributes.md +++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attributes.md @@ -1,2 +1,2 @@ # attributes -
    Column NameData TypeNullityDefault valueDescription
    attributeIdTextNon-null Unique Id of the attribute (e.g. qhC1vzU4nwSE), can also have a special unique ID for Special notes (e.g. _lbToday_liconClass).
    noteIdTextNon-null The ID of the note this atttribute belongs to
    typeTextNon-null The type of attribute (label or relation).
    nameTextNon-null The name/key of the attribute.
    valueTextNon-null""
    • For label attributes, a free-form value of the attribute.
    • For relation attributes, the ID of the note the relation is pointing to.
    positionIntegerNon-null0The position of the attribute compared to the other attributes. Some predefined attributes such as originalFileName have a value of 1000.
    utcDateModifiedTextNon-null Modification date in UTC format (e.g. 2023-11-08 16:43:44.204Z)
    isDeletedIntegerNon-null 1 if the entity is deleted, 0 otherwise.
    deleteIdTextNullablenull 
    isInheritableIntegerNullable0 
    \ No newline at end of file +
    Column NameData TypeNullityDefault valueDescription
    attributeIdTextNon-null Unique Id of the attribute (e.g. qhC1vzU4nwSE), can also have a special unique ID for Special notes (e.g. _lbToday_liconClass).
    noteIdTextNon-null The ID of the note this atttribute belongs to
    typeTextNon-null The type of attribute (label or relation).
    nameTextNon-null The name/key of the attribute.
    valueTextNon-null""
    • For label attributes, a free-form value of the attribute.
    • For relation attributes, the ID of the note the relation is pointing to.
    positionIntegerNon-null0The position of the attribute compared to the other attributes. Some predefined attributes such as originalFileName have a value of 1000.
    utcDateModifiedTextNon-null Modification date in UTC format (e.g. 2023-11-08 16:43:44.204Z)
    isDeletedIntegerNon-null 1 if the entity is deleted, 0 otherwise.
    deleteIdTextNullablenull 
    isInheritableIntegerNullable0 
    \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/blobs.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/blobs.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/blobs.md rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/blobs.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/branches.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/branches.md similarity index 82% rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/branches.md rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/branches.md index d9b12dea5..18cf29090 100644 --- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/branches.md +++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/branches.md @@ -5,8 +5,8 @@ | `noteId` | Text | Non-null | | The ID of the [note](notes.md). | | `parentNoteId` | Text | Non-null | | The ID of the parent [note](notes.md) the note belongs to. | | `notePosition` | Integer | Non-null | | The position of the branch within the same level of hierarchy, the value is usually a multiple of 10. | -| `prefix` | Text | Nullable | | The [branch prefix](../Branch%20prefixes.md) if any, or `NULL` otherwise. | +| `prefix` | Text | Nullable | | The [branch prefix](../../../Concepts/Branch%20prefixes.md) if any, or `NULL` otherwise. | | `isExpanded` | Integer | Non-null | 0 | Whether the branch should appear expanded (its children shown) to the user. | -| `isDeleted` | Integer | Non-null | 0 | `1` if the entity is [deleted](../Deleted%20notes.md), `0` otherwise. | +| `isDeleted` | Integer | Non-null | 0 | `1` if the entity is [deleted](../../../Concepts/Deleted%20notes.md), `0` otherwise. | | `deleteId` | Text | Nullable | `null` | | | `utcDateModified` | Text | Non-null | | Modification date in UTC format (e.g. `2023-11-08 16:43:44.204Z`) | \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/entity_changes.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/entity_changes.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/entity_changes.md rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/entity_changes.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/etapi_tokens.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/etapi_tokens.md similarity index 90% rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/etapi_tokens.md rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/etapi_tokens.md index 25fe4e5da..3f11dffa9 100644 --- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/etapi_tokens.md +++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/etapi_tokens.md @@ -6,4 +6,4 @@ | `tokenHash` | Text | Non-null | | The token itself. | | `utcDateCreated` | Text | Non-null | | Creation date in UTC format (e.g. `2023-11-08 16:43:44.204Z`) | | `utcDateModified` | Text | Non-null | | Modification date in UTC format (e.g. `2023-11-08 16:43:44.204Z`) | -| `isDeleted` | Integer | Non-null | 0 | `1` if the entity is [deleted](../Deleted%20notes.md), `0` otherwise. | \ No newline at end of file +| `isDeleted` | Integer | Non-null | 0 | `1` if the entity is [deleted](../../../Concepts/Deleted%20notes.md), `0` otherwise. | \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/notes.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/notes.md similarity index 90% rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/notes.md rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/notes.md index 572c7f6db..19cb4a322 100644 --- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/notes.md +++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/notes.md @@ -3,10 +3,10 @@ | --- | --- | --- | --- | --- | | `noteId` | Text | Non-null | | The unique ID of the note (e.g. `2LJrKqIhr0Pe`). | | `title` | Text | Non-null | `"note"` | The title of the note, as defined by the user. | -| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../Protected%20entities.md), `0` otherwise. | +| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../../../Concepts/Protected%20entities.md), `0` otherwise. | | `type` | Text | Non-null | `"text"` | The type of note (i.e. `text`, `file`, `code`, `relationMap`, `mermaid`, `canvas`). | | `mime` | Text | Non-null | `"text/html"` | The MIME type of the note (e.g. `text/html`).. Note that it can be an empty string in some circumstances, but not null. | -| `isDeleted` | Integer | Nullable | 0 | `1` if the entity is [deleted](../Deleted%20notes.md), `0` otherwise. | +| `isDeleted` | Integer | Nullable | 0 | `1` if the entity is [deleted](../../../Concepts/Deleted%20notes.md), `0` otherwise. | | `deleteId` | Text | Non-null | `null` | | | `dateCreated` | Text | Non-null | | Localized creation date (e.g. `2023-11-08 18:43:44.204+0200`) | | `dateModified` | Text | Non-null | | Localized modification date (e.g. `2023-11-08 18:43:44.204+0200`) | diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/options.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/options.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/options.md rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/options.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/recent_notes.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/recent_notes.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/recent_notes.md rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/recent_notes.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/revisions.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/revisions.md similarity index 94% rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/revisions.md rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/revisions.md index 210e05356..fef9ed1ed 100644 --- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/revisions.md +++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/revisions.md @@ -6,7 +6,7 @@ | `type` | Text | Non-null | `""` | The type of note (i.e. `text`, `file`, `code`, `relationMap`, `mermaid`, `canvas`). | | `mime` | Text | Non-null | `""` | The MIME type of the note (e.g. `text/html`). | | `title` | Text | Non-null | | The title of the note, as defined by the user. | -| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../Protected%20entities.md), `0` otherwise. | +| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../../../Concepts/Protected%20entities.md), `0` otherwise. | | `blobId` | Text | Nullable | `null` | The corresponding ID from blobs. Although it can theoretically be `NULL`, haven't found any such note yet. | | `utcDateLastEdited` | Text | Non-null | | **Not sure how it differs from modification date.** | | `utcDateCreated` | Text | Non-null | | Creation date in UTC format (e.g. `2023-11-08 16:43:44.204Z`) | diff --git a/docs/Developer Guide/Developer Guide/Architecture/Frontend.md b/docs/Developer Guide/Developer Guide/Architecture/Frontend.md new file mode 100644 index 000000000..9ef0acbdf --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Architecture/Frontend.md @@ -0,0 +1,61 @@ +# Frontend +### Application Entry Point + +**Desktop:** `apps/client/src/desktop.ts` **Web:** `apps/client/src/index.ts` + +### Service Layer + +Located at: `apps/client/src/services/` + +Key services: + +* `froca.ts` - Frontend cache +* `server.ts` - API communication +* `ws.ts` - WebSocket connection +* `tree_service.ts` - Note tree management +* `note_context.ts` - Active note tracking +* `protected_session.ts` - Encryption key management +* `link.ts` - Note linking and navigation +* `export.ts` - Note export functionality + +### UI Components + +**Component Locations:** + +* `widgets/containers/` - Layout containers +* `widgets/buttons/` - Toolbar buttons +* `widgets/dialogs/` - Modal dialogs +* `widgets/ribbon_widgets/` - Tab widgets +* `widgets/type_widgets/` - Note type editors + +### Event System + +**Application Events:** + +```typescript +// Subscribe to events +appContext.addBeforeUnloadListener(() => { + // Cleanup before page unload +}) + +// Trigger events +appContext.trigger('noteTreeLoaded') +``` + +**Note Context Events:** + +```typescript +// NoteContextAwareWidget automatically receives: +- noteSwitched() +- noteChanged() +- refresh() +``` + +### State Management + +Trilium uses **custom state management** rather than Redux/MobX: + +* `note_context.ts` - Active note and context +* `froca.ts` - Entity cache +* Component local state +* URL parameters for shareable state \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Protected entities.md b/docs/Developer Guide/Developer Guide/Architecture/Protected entities.md deleted file mode 100644 index f7d4e5b2e..000000000 --- a/docs/Developer Guide/Developer Guide/Architecture/Protected entities.md +++ /dev/null @@ -1,6 +0,0 @@ -# Protected entities -The following entities can be made protected, via their `isProtected` flag: - -* attachments -* notes -* revisions \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Security.md b/docs/Developer Guide/Developer Guide/Architecture/Security.md new file mode 100644 index 000000000..f1ef4da77 --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Architecture/Security.md @@ -0,0 +1,464 @@ +# Security +Trilium implements a **defense-in-depth security model** with multiple layers of protection for user data. The security architecture covers authentication, authorization, encryption, input sanitization, and secure communication. + +## Security Principles + +1. **Data Privacy**: User data is protected at rest and in transit +2. **Encryption**: Per-note encryption for sensitive content +3. **Authentication**: Multiple authentication methods supported +4. **Authorization**: Single-user model with granular protected sessions +5. **Input Validation**: All user input sanitized +6. **Secure Defaults**: Security features enabled by default +7. **Transparency**: Open source allows security audits + +## Threat Model + +### Threats Considered + +1. **Unauthorized Access** + * Physical access to device + * Network eavesdropping + * Stolen credentials + * Session hijacking +2. **Data Exfiltration** + * Malicious scripts + * XSS attacks + * SQL injection + * CSRF attacks +3. **Data Corruption** + * Malicious modifications + * Database tampering + * Sync conflicts +4. **Privacy Leaks** + * Unencrypted backups + * Search indexing + * Temporary files + * Memory dumps + +### Out of Scope + +* Nation-state attackers +* Zero-day vulnerabilities in dependencies +* Hardware vulnerabilities (Spectre, Meltdown) +* Physical access with unlimited time +* Quantum computing attacks + +## Authentication + +### Password Authentication + +**Implementation:** `apps/server/src/services/password.ts` + +### TOTP (Two-Factor Authentication) + +**Implementation:** `apps/server/src/routes/api/login.ts` + +### OpenID Connect + +**Implementation:** `apps/server/src/routes/api/login.ts` + +**Supported Providers:** + +* Any OpenID Connect compatible provider +* Google, GitHub, Auth0, etc. + +**Flow:** + +```typescript +// 1. Redirect to provider +GET /api/login/openid + +// 2. Provider redirects back with code +GET /api/login/openid/callback?code=... + +// 3. Exchange code for tokens +const tokens = await openidClient.callback(redirectUri, req.query) + +// 4. Verify ID token +const claims = tokens.claims() + +// 5. Create session +req.session.loggedIn = true +``` + +### Session Management + +**Session Storage:** SQLite database (sessions table) + +**Session Configuration:** + +```typescript +app.use(session({ + secret: sessionSecret, + resave: false, + saveUninitialized: false, + rolling: true, + cookie: { + maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days + httpOnly: true, + secure: isHttps, + sameSite: 'lax' + }, + store: new SqliteStore({ + db: db, + table: 'sessions' + }) +})) +``` + +**Session Invalidation:** + +* Automatic timeout after inactivity +* Manual logout clears session +* Server restart invalidates all sessions (optional) + +## Authorization + +### Single-User Model + +**Desktop:** + +* Single user (owner of device) +* No multi-user support +* Full access to all notes + +**Server:** + +* Single user per installation +* Authentication required for all operations +* No user roles or permissions + +### Protected Sessions + +**Purpose:** Temporary access to encrypted (protected) notes + +**Implementation:** `apps/server/src/services/protected_session.ts` + +**Workflow:** + +```typescript +// 1. User enters password for protected notes +POST /api/protected-session/enter +Body: { password: "protected-password" } + +// 2. Derive encryption key +const protectedDataKey = deriveKey(password) + +// 3. Verify password (decrypt known encrypted value) +const decrypted = decrypt(testValue, protectedDataKey) +if (decrypted === expectedValue) { + // 4. Store in memory (not in session) + protectedSessionHolder.setProtectedDataKey(protectedDataKey) + + // 5. Set timeout + setTimeout(() => { + protectedSessionHolder.clearProtectedDataKey() + }, timeout) +} +``` + +**Protected Session Timeout:** + +* Default: 10 minutes (configurable) +* Extends on activity +* Cleared on browser close +* Separate from main session + +### API Authorization + +**Internal API:** + +* Requires authenticated session +* CSRF token validation +* Same-origin policy + +**ETAPI (External API):** + +* Token-based authentication +* No session required +* Rate limiting + +## Encryption + +### Note Encryption + +**Encryption Algorithm:** AES-256-CBC + +**Key Hierarchy:** + +``` +User Password + ↓ (scrypt) +Data Key (for protected notes) + ↓ (AES-128) +Protected Note Content +``` + +**Protected Note Metadata:** + +* Content IS encrypted +* Type and MIME are NOT encrypted +* Attributes are NOT encrypted + +### Data Key Management + +**Key Rotation:** + +* Not currently supported +* Requires re-encrypting all protected notes + +### Transport Encryption + +**HTTPS:** + +* Recommended for server installations +* TLS 1.2+ only +* Strong cipher suites preferred +* Certificate validation enabled + +**Desktop:** + +* Local communication (no network) +* No HTTPS required + +### Backup Encryption + +**Database Backups:** + +* Protected notes remain encrypted in backup +* Backup file should be protected separately +* Consider encrypting backup storage location + +## Input Sanitization + +### XSS Prevention + +* **HTML Sanitization** +* **CKEditor Configuration:** + + ``` + // apps/client/src/widgets/type_widgets/text_type_widget.ts + ClassicEditor.create(element, { + // Restrict allowed content + htmlSupport: { + allow: [ + { name: /./, attributes: true, classes: true, styles: true } + ], + disallow: [ + { name: 'script' }, + { name: 'iframe', attributes: /^(?!src$).*/ } + ] + } + }) + ``` +* Content Security Policy + +### SQL Injection Prevention + +**Parameterized Queries:** + +```typescript +const notes = sql.getRows( + 'SELECT * FROM notes WHERE title = ?', + [userInput] +) +``` + +**ORM Usage:** + +```typescript +// Entity-based access prevents SQL injection +const note = becca.getNote(noteId) +note.title = userInput // Sanitized by entity +note.save() // Parameterized query +``` + +### CSRF Prevention + +**CSRF Token Validation:** + +Location: `apps/server/src/routes/csrf_protection.ts` + +Stateless CSRF using [Double Submit Cookie Pattern](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie) via [`csrf-csrf`](https://github.com/Psifi-Solutions/csrf-csrf). + +### File Upload Validation + +**Validation:** + +```typescript +// Validate file size +const maxSize = 100 * 1024 * 1024 // 100 MB +if (file.size > maxSize) { + throw new Error('File too large') +} +``` + +## Network Security + +### HTTPS Configuration + +**Certificate Validation:** + +* Require valid certificates in production +* Self-signed certificates allowed for development +* Certificate pinning not implemented + +### Rate Limiting + +**Login Rate Limiting:** + +```typescript +const loginLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, + max: 10, // 10 failed attempts + skipSuccessfulRequests: true +}) + +app.post('/api/login/password', loginLimiter, loginHandler) +``` + +## Data Security + +### Secure Data Deletion + +**Soft Delete:** + +```typescript +// Mark as deleted (sync first) +note.isDeleted = 1 +note.deleteId = generateUUID() +note.save() + +// Entity change tracked for sync +addEntityChange('notes', noteId, note) +``` + +**Hard Delete (Erase):** + +```typescript +// After sync completed +sql.execute('DELETE FROM notes WHERE noteId = ?', [noteId]) +sql.execute('DELETE FROM branches WHERE noteId = ?', [noteId]) +sql.execute('DELETE FROM attributes WHERE noteId = ?', [noteId]) + +// Mark entity change as erased +sql.execute('UPDATE entity_changes SET isErased = 1 WHERE entityId = ?', [noteId]) +``` + +**Blob Cleanup:** + +```typescript +// Find orphaned blobs (not referenced by any note/revision/attachment) +const orphanedBlobs = sql.getRows(` + SELECT blobId FROM blobs + WHERE blobId NOT IN (SELECT blobId FROM notes WHERE blobId IS NOT NULL) + AND blobId NOT IN (SELECT blobId FROM revisions WHERE blobId IS NOT NULL) + AND blobId NOT IN (SELECT blobId FROM attachments WHERE blobId IS NOT NULL) +`) + +// Delete orphaned blobs +for (const blob of orphanedBlobs) { + sql.execute('DELETE FROM blobs WHERE blobId = ?', [blob.blobId]) +} +``` + +### Memory Security + +**Protected Data in Memory:** + +* Protected data keys stored in memory only +* Cleared on timeout +* Not written to disk +* Not in session storage + +## Dependency Security + +### Vulnerability Scanning + +**Tools:** + +* Renovate bot - Automatic dependency updates +* `pnpm audit` - Check for known vulnerabilities +* GitHub Dependabot alerts + +**Process:** + +``` +# Check for vulnerabilities +npm audit + +# Fix automatically +npm audit fix + +# Manual review for breaking changes +npm audit fix --force +``` + +### Dependency Pinning + +**package.json:** + +``` +{ + "dependencies": { + "express": "4.18.2", // Exact version + "better-sqlite3": "^9.2.2" // Compatible versions + } +} +``` + +**pnpm Overrides:** + +``` +{ + "pnpm": { + "overrides": { + "lodash@<4.17.21": ">=4.17.21", // Force minimum version + "axios@<0.21.2": ">=0.21.2" + } + } +} +``` + +### Patch Management + +**pnpm Patches:** + +``` +# Create patch +pnpm patch @ckeditor/ckeditor5 + +# Edit files in temporary directory +# ... + +# Generate patch file +pnpm patch-commit /tmp/ckeditor5-patch + +# Patch applied automatically on install +``` + +## Security Auditing + +### Logs + +**Security Events Logged:** + +* Login attempts (success/failure) +* Protected session access +* Password changes +* ETAPI token usage +* Failed CSRF validations + +**Log Location:** + +* Desktop: Console output +* Server: Log files or stdout + +### Monitoring + +**Metrics to Monitor:** + +* Failed login attempts +* API error rates +* Unusual database changes +* Large exports/imports \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Building/Documentation.md b/docs/Developer Guide/Developer Guide/Building/Documentation.md deleted file mode 100644 index bd3124b55..000000000 --- a/docs/Developer Guide/Developer Guide/Building/Documentation.md +++ /dev/null @@ -1,17 +0,0 @@ -# Documentation -## Automation - -The documentation is built via `apps/build-docs`: - -1. The output directory is cleared. -2. The User Guide and the Developer Guide are built. - 1. The documentation from the repo is archived and imported into an in-memory instance. - 2. The documentation is exported using the shared theme. -3. The API docs (internal and ETAPI) are statically rendered via Redocly. -4. The script API is generated via `typedoc` - -The `deploy-docs` workflow triggers the documentation build and uploads it to CloudFlare Pages. - -## Building locally - -In the Git root, run `pnpm docs:build`. The built documentation will be available in `site` at Git root. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Building/Releasing a new version.md b/docs/Developer Guide/Developer Guide/Building/Releasing a new version.md new file mode 100644 index 000000000..19e3427ec --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Building/Releasing a new version.md @@ -0,0 +1,19 @@ +# Releasing a new version +Releasing is mostly handled by the CI: + +* The version on GitHub is published automatically, including the description with the change log which is taken from the documentation. +* A PR is created automatically on the Winget repository to update to the new version. + +Releases are usually made directly from the `main` branch. + +The process is as follows: + +1. Edit the Documentation to add a corresponding entry in the _Release notes_ section. +2. In the root `package.json`, set `version` to the new version to be released. +3. Run `chore:update-version` to automatically update the version of the rest of the `package.json` files. +4. Run `pnpm i` to update the package lock as well. +5. Commit the changes to the `package.json` files and the `package-lock.json`. The commit message is usually `chore(release): prepare for v1.2.3`. +6. Tag the newly created commit: `git tag v1.2.3` +7. Push the commit and the newly created tag: `git push; git push --tags`. +8. Wait for the CI to finish. +9. When the release is automatically created in GitHub, download it to make sure it works OK. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Backlinks.md b/docs/Developer Guide/Developer Guide/Concepts/Backlinks.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Backlinks.md rename to docs/Developer Guide/Developer Guide/Concepts/Backlinks.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Branch prefixes.md b/docs/Developer Guide/Developer Guide/Concepts/Branch prefixes.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Branch prefixes.md rename to docs/Developer Guide/Developer Guide/Concepts/Branch prefixes.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/CI/1_Main_image.png b/docs/Developer Guide/Developer Guide/Concepts/CI/1_Main_image.png similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/CI/1_Main_image.png rename to docs/Developer Guide/Developer Guide/Concepts/CI/1_Main_image.png diff --git a/docs/Developer Guide/Developer Guide/Architecture/CI/Main.md b/docs/Developer Guide/Developer Guide/Concepts/CI/Main.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/CI/Main.md rename to docs/Developer Guide/Developer Guide/Concepts/CI/Main.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/CI/Main_image.png b/docs/Developer Guide/Developer Guide/Concepts/CI/Main_image.png similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/CI/Main_image.png rename to docs/Developer Guide/Developer Guide/Concepts/CI/Main_image.png diff --git a/docs/Developer Guide/Developer Guide/Concepts/Cache.md b/docs/Developer Guide/Developer Guide/Concepts/Cache.md new file mode 100644 index 000000000..91a6f8b6d --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Concepts/Cache.md @@ -0,0 +1,111 @@ +# Cache +### Three-Layer Cache System + +Trilium implements a sophisticated **three-tier caching system** to optimize performance and enable offline functionality: + +#### 1\. Becca (Backend Cache) + +Located at: `apps/server/src/becca/` + +```typescript +// Becca caches all entities in memory +class Becca { + notes: Record + branches: Record + attributes: Record + attachments: Record + // ... other entity collections +} +``` + +**Responsibilities:** + +* Server-side entity cache +* Maintains complete note tree in memory +* Handles entity relationships and integrity +* Provides fast lookups without database queries +* Manages entity lifecycle (create, update, delete) + +**Key Files:** + +* `becca.ts` - Main cache instance +* `becca_loader.ts` - Loads entities from database +* `becca_service.ts` - Cache management operations +* `entities/` - Entity classes (BNote, BBranch, etc.) + +#### 2\. Froca (Frontend Cache) + +Located at: `apps/client/src/services/froca.ts` + +```typescript +// Froca is a read-only mirror of backend data +class Froca { + notes: Record + branches: Record + attributes: Record + // ... other entity collections +} +``` + +**Responsibilities:** + +* Frontend read-only cache +* Lazy loading of note tree +* Minimizes API calls +* Enables fast UI rendering +* Synchronizes with backend via WebSocket + +**Loading Strategy:** + +* Initial load: root notes and immediate children +* Lazy load: notes loaded when accessed +* When note is loaded, all parent and child branches load +* Deleted entities tracked via missing branches + +#### 3\. Shaca (Share Cache) + +Located at: `apps/server/src/share/` + +**Responsibilities:** + +* Optimized cache for shared/published notes +* Handles public note access without authentication +* Performance-optimized for high-traffic scenarios +* Separate from main Becca to isolate concerns + +### Cache Invalidation + +**Server-Side:** + +* Entities automatically update cache on save +* WebSocket broadcasts changes to all clients +* Synchronization updates trigger cache refresh + +**Client-Side:** + +* WebSocket listeners update Froca +* Manual reload via `froca.loadSubTree(noteId)` +* Full reload on protected session changes + +### Cache Consistency + +**Entity Change Tracking:** + +```typescript +// Every entity modification tracked +entity_changes ( + entityName: 'notes', + entityId: 'note123', + hash: 'abc...', + changeId: 'change456', + utcDateChanged: '2025-11-02...' +) +``` + +**Sync Protocol:** + +1. Client requests changes since last sync +2. Server returns entity\_changes records +3. Client applies changes to Froca +4. Client sends local changes to server +5. Server updates Becca and database \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Deleted notes.md b/docs/Developer Guide/Developer Guide/Concepts/Deleted notes.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Deleted notes.md rename to docs/Developer Guide/Developer Guide/Concepts/Deleted notes.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Demo document.md b/docs/Developer Guide/Developer Guide/Concepts/Demo document.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Demo document.md rename to docs/Developer Guide/Developer Guide/Concepts/Demo document.md diff --git a/docs/Developer Guide/Developer Guide/Concepts/Entities.md b/docs/Developer Guide/Developer Guide/Concepts/Entities.md new file mode 100644 index 000000000..faac90af7 --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Concepts/Entities.md @@ -0,0 +1,109 @@ +# Entities +### Entity System + +Trilium's data model is based on five core entities: + +``` +graph TD + Note[Note
    BNote] + Branch[Branch
    BBranch] + Attribute[Attribute
    BAttribute] + Revision[Revision
    BRevision] + Attachment[Attachment
    BAttachment] + + Note -->|linked by| Branch + Note -.->|metadata| Attribute + Branch -->|creates| Revision + Note -->|has| Attachment + + style Note fill:#e1f5ff + style Branch fill:#fff4e1 + style Attribute fill:#ffe1f5 + style Revision fill:#f5ffe1 + style Attachment fill:#ffe1e1 +``` + +#### Entity Definitions + +**1\. BNote** (`apps/server/src/becca/entities/bnote.ts`) + +* Represents a note with title, content, and metadata +* Type can be: text, code, file, image, canvas, mermaid, etc. +* Contains content via blob reference +* Can be protected (encrypted) +* Has creation and modification timestamps + +**2\. BBranch** (`apps/server/src/becca/entities/bbranch.ts`) + +* Represents parent-child relationship between notes +* Enables note cloning (multiple parents) +* Contains positioning information +* Has optional prefix for customization +* Tracks expansion state in tree + +**3\. BAttribute** (`apps/server/src/becca/entities/battribute.ts`) + +* Key-value metadata attached to notes +* Two types: labels (tags) and relations (links) +* Can be inheritable to child notes +* Used for search, organization, and scripting +* Supports promoted attributes (displayed prominently) + +**4\. BRevision** (`apps/server/src/becca/entities/brevision.ts`) + +* Stores historical versions of note content +* Automatic versioning on edits +* Retains title, type, and content +* Enables note history browsing and restoration + +**5\. BAttachment** (`apps/server/src/becca/entities/battachment.ts`) + +* File attachments linked to notes +* Has owner (note), role, and mime type +* Content stored in blobs +* Can be protected (encrypted) + +**6\. BBlob** (`apps/server/src/becca/entities/bblob.ts`) + +* Binary large object storage +* Stores actual note content and attachments +* Referenced by notes, revisions, and attachments +* Supports encryption for protected content + +### Widget-Based UI + +The frontend uses a **widget system** for modular, reusable UI components. + +Located at: `apps/client/src/widgets/` + +```typescript +// Widget Hierarchy +BasicWidget +├── NoteContextAwareWidget (responds to note changes) +│ ├── RightPanelWidget (displayed in right sidebar) +│ └── Type-specific widgets +├── Container widgets (tabs, ribbons, etc.) +└── Specialized widgets (search, calendar, etc.) +``` + +**Base Classes:** + +1. **BasicWidget** (`basic_widget.ts`) + * Base class for all UI components + * Lifecycle: construction → rendering → events → destruction + * Handles DOM manipulation + * Event subscription management + * Child widget management +2. **NoteContextAwareWidget** (`note_context_aware_widget.ts`) + * Extends BasicWidget + * Automatically updates when active note changes + * Accesses current note context + * Used for note-dependent UI +3. **RightPanelWidget** + * Widgets displayed in right sidebar + * Collapsible sections + * Context-specific tools and information + +**Type-Specific Widgets:** + +Each note type has a dedicated widget, which are located in `apps/client/src/widgets/type_widgets`. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Hidden notes.md b/docs/Developer Guide/Developer Guide/Concepts/Hidden notes.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Hidden notes.md rename to docs/Developer Guide/Developer Guide/Concepts/Hidden notes.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Icons.md b/docs/Developer Guide/Developer Guide/Concepts/Icons.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Icons.md rename to docs/Developer Guide/Developer Guide/Concepts/Icons.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translat.md b/docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translat.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translat.md rename to docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translat.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/Guidelines.md b/docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/Guidelines.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/Guidelines.md rename to docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/Guidelines.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/Server translations.md b/docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/Server translations.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/Server translations.md rename to docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/Server translations.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/i18n-ally.md b/docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/i18n-ally.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/i18n-ally.md rename to docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/i18n-ally.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Launchers.md b/docs/Developer Guide/Developer Guide/Concepts/Launchers.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Launchers.md rename to docs/Developer Guide/Developer Guide/Concepts/Launchers.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Revisions.md b/docs/Developer Guide/Developer Guide/Concepts/Note Revisions.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Note Revisions.md rename to docs/Developer Guide/Developer Guide/Concepts/Note Revisions.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Copy image reference to the cl.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Copy image reference to the cl.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Copy image reference to the cl.md rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Copy image reference to the cl.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Export diagram as SVG.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Export diagram as SVG.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Export diagram as SVG.md rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Export diagram as SVG.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/First steps.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/First steps.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/First steps.md rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/First steps.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/First steps/mind_map.js b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/First steps/mind_map.js similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/First steps/mind_map.js rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/First steps/mind_map.js diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Loading data.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Loading data.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Loading data.md rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Loading data.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Note type checklist.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Note type checklist.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Note type checklist.md rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Note type checklist.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/SVG rendering.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/SVG rendering.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/SVG rendering.md rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/SVG rendering.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Saving data via spaced update.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Saving data via spaced update.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Saving data via spaced update.md rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Saving data via spaced update.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Options.md b/docs/Developer Guide/Developer Guide/Concepts/Options.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Options.md rename to docs/Developer Guide/Developer Guide/Concepts/Options.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Options/Creating a new option.md b/docs/Developer Guide/Developer Guide/Concepts/Options/Creating a new option.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Options/Creating a new option.md rename to docs/Developer Guide/Developer Guide/Concepts/Options/Creating a new option.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Printing and exporting to PDF.md b/docs/Developer Guide/Developer Guide/Concepts/Printing and exporting to PDF.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Printing and exporting to PDF.md rename to docs/Developer Guide/Developer Guide/Concepts/Printing and exporting to PDF.md diff --git a/docs/Developer Guide/Developer Guide/Concepts/Protected entities.md b/docs/Developer Guide/Developer Guide/Concepts/Protected entities.md new file mode 100644 index 000000000..31d5250c0 --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Concepts/Protected entities.md @@ -0,0 +1,6 @@ +# Protected entities +The following entities can be made protected, via their `isProtected` flag: + +* attachments +* notes +* revisions \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Share.md b/docs/Developer Guide/Developer Guide/Concepts/Share.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Share.md rename to docs/Developer Guide/Developer Guide/Concepts/Share.md diff --git a/docs/Developer Guide/Developer Guide/Concepts/Synchronisation.md b/docs/Developer Guide/Developer Guide/Concepts/Synchronisation.md new file mode 100644 index 000000000..45a520cb6 --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Concepts/Synchronisation.md @@ -0,0 +1,484 @@ +# Synchronisation +Trilium implements a **bidirectional synchronization system** that allows users to sync their note databases across multiple devices (desktop clients and server instances). The sync protocol is designed to handle: + +* Concurrent modifications across devices +* Simple conflict resolution (without “merge conflict” indication). +* Partial sync (only changed entities) +* Protected note synchronization +* Efficient bandwidth usage + +## Sync Architecture + +``` +graph TB + Desktop1[Desktop 1
    Client] + Desktop2[Desktop 2
    Client] + + subgraph SyncServer["Sync Server"] + SyncService[Sync Service
    - Entity Change Management
    - Conflict Resolution
    - Version Tracking] + SyncDB[(Database
    entity_changes)] + end + + Desktop1 <-->|WebSocket/HTTP| SyncService + Desktop2 <-->|WebSocket/HTTP| SyncService + SyncService --> SyncDB +``` + +## Core Concepts + +### Entity Changes + +Every modification to any entity (note, branch, attribute, etc.) creates an **entity change** record: + +``` +entity_changes ( + id, -- Auto-increment ID + entityName, -- 'notes', 'branches', 'attributes', etc. + entityId, -- ID of the changed entity + hash, -- Content hash for integrity + isErased, -- If entity was erased (deleted permanently) + changeId, -- Unique change identifier + componentId, -- Unique component/widget identifier + instanceId, -- Process instance identifier + isSynced, -- Whether synced to server + utcDateChanged -- When change occurred +) +``` + +**Key Properties:** + +* **changeId**: Globally unique identifier (UUID) for the change +* **componentId**: Unique identifier of the component/widget that generated to change (can be used to avoid refreshing the widget being edited). +* **instanceId**: Unique per process (changes on restart) +* **hash**: SHA-256 hash of entity data for integrity verification + +### Sync Versions + +Each Trilium installation tracks: + +* **Local sync version**: Highest change ID seen locally +* **Server sync version**: Highest change ID on server +* **Entity versions**: Last sync version for each entity type + +### Change Tracking + +**When an entity is modified:** + +```typescript +// apps/server/src/services/entity_changes.ts +function addEntityChange(entityName, entityId, entity) { + const hash = calculateHash(entity) + const changeId = generateUUID() + + sql.insert('entity_changes', { + entityName, + entityId, + hash, + changeId, + componentId: config.componentId, + instanceId: config.instanceId, + isSynced: 0, + utcDateChanged: now() + }) +} +``` + +**Entity modification triggers:** + +* Note content update +* Note metadata change +* Branch creation/deletion/reorder +* Attribute addition/removal +* Options modification + +## Sync Protocol + +### Sync Handshake + +**Step 1: Client Initiates Sync** + +```typescript +// Client sends current sync version +POST /api/sync/check +{ + "sourceId": "client-component-id", + "maxChangeId": 12345 +} +``` + +**Step 2: Server Responds with Status** + +```typescript +// Server checks for changes +Response: +{ + "entityChanges": 567, // Changes on server + "maxChangeId": 12890, // Server's max change ID + "outstandingPushCount": 23 // Client changes not yet synced +} +``` + +**Step 3: Decision** + +* If `entityChanges > 0`: Pull changes from server +* If `outstandingPushCount > 0`: Push changes to server +* Both can happen in sequence + +### Pull Sync (Server → Client) + +**Client Requests Changes:** + +```typescript +POST /api/sync/pull +{ + "sourceId": "client-component-id", + "lastSyncedChangeId": 12345 +} +``` + +**Server Responds:** + +```typescript +Response: +{ + "notes": [ + { noteId: "abc", title: "New Note", ... } + ], + "branches": [...], + "attributes": [...], + "revisions": [...], + "attachments": [...], + "entityChanges": [ + { entityName: "notes", entityId: "abc", changeId: "...", ... } + ], + "maxChangeId": 12890 +} +``` + +**Client Processing:** + +1. Apply entity changes to local database +2. Update Froca cache +3. Update local sync version +4. Trigger UI refresh + +### Push Sync (Client → Server) + +**Client Sends Changes:** + +```typescript +POST /api/sync/push +{ + "sourceId": "client-component-id", + "entities": [ + { + "entity": { + "noteId": "xyz", + "title": "Modified Note", + ... + }, + "entityChange": { + "changeId": "change-uuid", + "entityName": "notes", + ... + } + } + ] +} +``` + +**Server Processing:** + +1. Validate changes +2. Check for conflicts +3. Apply changes to database +4. Update Becca cache +5. Mark as synced +6. Broadcast to other connected clients via WebSocket + +**Conflict Detection:** + +```typescript +// Check if entity was modified on server since client's last sync +const serverEntity = becca.getNote(noteId) +const serverLastModified = serverEntity.utcDateModified + +if (serverLastModified > clientSyncVersion) { + // CONFLICT! + resolveConflict(serverEntity, clientEntity) +} +``` + +## Conflict Resolution + +### Conflict Types + +**1\. Content Conflict** + +* Both client and server modified same note content +* **Resolution**: Last-write-wins based on `utcDateModified` + +**2\. Structure Conflict** + +* Branch moved/deleted on one side, modified on other +* **Resolution**: Tombstone records, reconciliation + +**3\. Attribute Conflict** + +* Same attribute modified differently +* **Resolution**: Last-write-wins + +### Conflict Resolution Strategy + +**Last-Write-Wins:** + +```typescript +if (clientEntity.utcDateModified > serverEntity.utcDateModified) { + // Client wins, apply client changes + applyClientChange(clientEntity) +} else { + // Server wins, reject client change + // Client will pull server version on next sync +} +``` + +**Tombstone Records:** + +* Deleted entities leave tombstone in `entity_changes` +* Prevents re-sync of deleted items +* `isErased = 1` for permanent deletions + +### Protected Notes Sync + +**Challenge:** Encrypted content can't be synced without password + +**Solution:** + +1. **Encrypted sync**: Content synced in encrypted form +2. **Hash verification**: Integrity checked without decryption +3. **Lazy decryption**: Only decrypt when accessed + +## Sync States + +### Connection States + +* **Connected**: WebSocket connection active +* **Disconnected**: No connection to sync server +* **Syncing**: Actively transferring data +* **Conflict**: Sync paused due to conflict + +### Entity Sync States + +Each entity can be in: + +* **Synced**: In sync with server +* **Pending**: Local changes not yet pushed +* **Conflict**: Conflicting changes detected + +### UI Indicators + +```typescript +// apps/client/src/widgets/sync_status.ts +class SyncStatusWidget { + showSyncStatus() { + if (isConnected && allSynced) { + showIcon('synced') + } else if (isSyncing) { + showIcon('syncing-spinner') + } else { + showIcon('not-synced') + } + } +} +``` + +## Performance Optimizations + +### Incremental Sync + +Only entities changed since last sync are transferred: + +``` +SELECT * FROM entity_changes +WHERE id > :lastSyncedChangeId +ORDER BY id ASC +LIMIT 1000 +``` + +### Batch Processing + +Changes sent in batches to reduce round trips: + +```typescript +const BATCH_SIZE = 1000 +const changes = getUnsyncedChanges(BATCH_SIZE) +await syncBatch(changes) +``` + +### Hash-Based Change Detection + +```typescript +// Only sync if hash differs +const localHash = calculateHash(localEntity) +const serverHash = getServerHash(entityId) + +if (localHash !== serverHash) { + syncEntity(localEntity) +} +``` + +### Compression + +Large payloads compressed before transmission: + +```typescript +// Server sends compressed response +res.setHeader('Content-Encoding', 'gzip') +res.send(gzip(syncData)) +``` + +## Error Handling + +### Network Errors + +Reported to the user and the sync will be retried after the interval passes. + +### Sync Integrity Checks + +**Hash Verification:** + +```typescript +// Verify entity hash matches +const calculatedHash = calculateHash(entity) +const receivedHash = entityChange.hash + +if (calculatedHash !== receivedHash) { + throw new Error('Hash mismatch - data corruption detected') +} +``` + +**Consistency Checks:** + +* Orphaned branches detection +* Missing parent notes +* Invalid entity references +* Circular dependencies + +## Sync Server Configuration + +### Server Setup + +**Required Options:** + +```javascript +{ + "syncServerHost": "https://sync.example.com", + "syncServerTimeout": 60000, + "syncProxy": "" // Optional HTTP proxy +} +``` + +**Authentication:** + +* Username/password or +* Sync token (generated on server) + +## Sync API Endpoints + +Located at: `apps/server/src/routes/api/sync.ts` + +## WebSocket Sync Updates + +Real-time sync via WebSocket: + +```typescript +// Server broadcasts change to all connected clients +ws.broadcast('frontend-update', { + lastSyncedPush, + entityChanges +}) + +// Client receives and processed the information. +``` + +## Sync Scheduling + +### Automatic Sync + +**Desktop:** + +* Sync on startup +* Periodic sync (configurable interval, default: 60s) + +**Server:** + +* Sync on entity modification +* WebSocket push to connected clients + +### Manual Sync + +User can trigger: + +* Full sync +* Sync now +* Sync specific subtree + +## Troubleshooting + +### Common Issues + +**Sync stuck:** + +``` +-- Reset sync state +UPDATE entity_changes SET isSynced = 0; +DELETE FROM options WHERE name LIKE 'sync%'; +``` + +**Hash mismatch:** + +* Data corruption detected +* Re-sync from backup +* Check database integrity + +**Conflict loop:** + +* Manual intervention required +* Export conflicting notes +* Choose winning version +* Re-sync + +## Security Considerations + +### Encrypted Sync + +* Protected notes synced encrypted +* No plain text over network +* Server cannot read protected content + +### Authentication + +* Username/password over HTTPS only +* Sync tokens for token-based auth +* Session cookies with CSRF protection + +### Authorization + +* Users can only sync their own data +* No cross-user sync support +* Sync server validates ownership + +## Performance Metrics + +**Typical Sync Performance:** + +* 1000 changes: ~2-5 seconds +* 10000 changes: ~20-50 seconds +* Initial full sync (100k notes): ~5-10 minutes + +**Factors:** + +* Network latency +* Database size +* Number of protected notes +* Attachment sizes \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Architecture/Synchronisation/Content hashing.md b/docs/Developer Guide/Developer Guide/Concepts/Synchronisation/Content hashing.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Synchronisation/Content hashing.md rename to docs/Developer Guide/Developer Guide/Concepts/Synchronisation/Content hashing.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Syntax highlighting.md b/docs/Developer Guide/Developer Guide/Concepts/Syntax highlighting.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Syntax highlighting.md rename to docs/Developer Guide/Developer Guide/Concepts/Syntax highlighting.md diff --git a/docs/Developer Guide/Developer Guide/Architecture/Themes.md b/docs/Developer Guide/Developer Guide/Concepts/Themes.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Architecture/Themes.md rename to docs/Developer Guide/Developer Guide/Concepts/Themes.md diff --git a/docs/Developer Guide/Developer Guide/Project Structure/CKEditor.md b/docs/Developer Guide/Developer Guide/Dependencies/CKEditor.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Project Structure/CKEditor.md rename to docs/Developer Guide/Developer Guide/Dependencies/CKEditor.md diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Differences from upstream.md b/docs/Developer Guide/Developer Guide/Dependencies/CKEditor/Differences from upstream.md similarity index 81% rename from docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Differences from upstream.md rename to docs/Developer Guide/Developer Guide/Dependencies/CKEditor/Differences from upstream.md index a5230d8f7..d8e2db46b 100644 --- a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Differences from upstream.md +++ b/docs/Developer Guide/Developer Guide/Dependencies/CKEditor/Differences from upstream.md @@ -1,5 +1,5 @@ # Differences from upstream -* Embeds [`~~isaul32/ckeditor5-math~~`](https://github.com/isaul32/ckeditor5-math)  ckeditor5-math, which is a third-party plugin for adding math support. CKEditor itself also has a [math plugin](https://ckeditor.com/docs/ckeditor5/latest/features/math-equations.html) with MathType and ChemType but it's premium-only. +* Embeds [`~~isaul32/ckeditor5-math~~`](https://github.com/isaul32/ckeditor5-math)  ckeditor5-math, which is a third-party plugin for adding math support. CKEditor itself also has a [math plugin](https://ckeditor.com/docs/ckeditor5/latest/features/math-equations.html) with MathType and ChemType but it's premium-only. * Zadam left a TODO in `findandreplaceUI`: `// FIXME: keyboard shortcut doesn't work:` [`https://github.com/ckeditor/ckeditor5/issues/10645`](https://github.com/ckeditor/ckeditor5/issues/10645) * `packages\ckeditor5-build-balloon-block\src\mention_customization.js` introduces note insertion via `@` character. diff --git a/docs/Developer Guide/Developer Guide/Project Structure/CKEditor/Plugin migration guide.md b/docs/Developer Guide/Developer Guide/Dependencies/CKEditor/Plugin migration guide.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Project Structure/CKEditor/Plugin migration guide.md rename to docs/Developer Guide/Developer Guide/Dependencies/CKEditor/Plugin migration guide.md diff --git a/docs/Developer Guide/Developer Guide/Dependencies/CKEditor/ckeditor5-math.md b/docs/Developer Guide/Developer Guide/Dependencies/CKEditor/ckeditor5-math.md new file mode 100644 index 000000000..e47a59f12 --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Dependencies/CKEditor/ckeditor5-math.md @@ -0,0 +1,16 @@ +# ckeditor5-math +

    ckeditor5-math in action.
    + +A fork of [isaul32/ckeditor5-math](https://github.com/isaul32/ckeditor5-math), which is the CKEditor5 plugin which adds the math functionality. We keep our own version to be able to use it on the latest version of CKEditor, alongside some custom improvements. + +## Development environment + +* Tested on Node.js 20. +* The package manager is yarn 1 (v1.22.22 is known to be working fine for it at the time of writing). + +Important commands: + +* To check if the code has any formatting issues: `yarn lint` +* To start a live preview: `yarn start` +* To run the tests: `yarn test` + * Note that this requires Chromium, on NixOS this can be achieved by running a `nix-shell -p chromium`, and running `CHROME_BIN=$(which chromium) yarn test` inside it. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/ckeditor5-math_image.png b/docs/Developer Guide/Developer Guide/Dependencies/CKEditor/ckeditor5-math_image.png similarity index 100% rename from docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/ckeditor5-math_image.png rename to docs/Developer Guide/Developer Guide/Dependencies/CKEditor/ckeditor5-math_image.png diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Project maintenance/Updating dependencies.md b/docs/Developer Guide/Developer Guide/Dependencies/Per-dependency checks.md similarity index 96% rename from docs/Developer Guide/Developer Guide/Old documentation/Project maintenance/Updating dependencies.md rename to docs/Developer Guide/Developer Guide/Dependencies/Per-dependency checks.md index fb27cb6bf..309042ffc 100644 --- a/docs/Developer Guide/Developer Guide/Old documentation/Project maintenance/Updating dependencies.md +++ b/docs/Developer Guide/Developer Guide/Dependencies/Per-dependency checks.md @@ -1,2 +1,2 @@ -# Updating dependencies -
    DependencyName in library_loaderThings to check for a basic sanity check Protected by unit tests
    better-sqlite3 See bettersqlite binaries.  
    jsdom 
    • Note map
    • Clipper
    • Note similarity
    Protected by typings, should catch any potential changes in API.Yes
    async-mutex 
    • Sync
      
    axios 
    • Can't be directly tested, as it's exposed only via the backend script API.
      
    sax 
    • EverNote imports
      
    • ws
    • debounce
     
    • Check any action is reported from server to client (e.g. delete a note).
      
    ejs 
    • Onboarding / first setup
      
    dayjs 
    • Day notes
      
    semver 
    • Application should start.
      
    https-proxy-agent ???  
    sax 
    • EverNote import
      
    ini 
    • Affects config, generally if the application starts then it should be OK.
      
    jsplumbRELATION_MAP
    • Relation map note type
      
    jquery.mark.es6MARKJS
    • In search, when highlighting the text that matched.
    • In search in HTML, which might not actually be used since it seems to have been replaced by CKEditor's own find & replace dialog.
      
    knockout.js 
    • Used in rendering the login and main layout of the application.
      
    normalize.min.css 
    • Used in shared notes.
      
    wheel-zoom.min.jsWHEEL_ZOOM
    • When opening a image that is in attachment.
    • When opening a stand-alone image note.
    • When zooming in a mermaid chart.
      
    fancytree 
    • The note tree should be fully functional.
      
    bootstrap 
    • Check mostly the on-boarding pages, when there is no database.
      
    electron-debug 
    • Run electron using npm run start-electron and check that the debug hotkeys are still working (Ctrl+Shift+I on Windows/Linux, Cmd+Alt+I for dev tools, Cmd/Ctrl+R for reload).
      
    electron-dl    
    eslint    
    marked 
    • Importing a markdown note.
     Yes
    force-graph 
    • Note map
      
    \ No newline at end of file +# Per-dependency checks +
    DependencyName in library_loaderThings to check for a basic sanity check Protected by unit tests
    better-sqlite3 See bettersqlite binaries.  
    jsdom 
    • Note map
    • Clipper
    • Note similarity
    Protected by typings, should catch any potential changes in API.Yes
    async-mutex 
    • Sync
      
    axios 
    • Can't be directly tested, as it's exposed only via the backend script API.
      
    sax 
    • EverNote imports
      
    • ws
    • debounce
     
    • Check any action is reported from server to client (e.g. delete a note).
      
    ejs 
    • Onboarding / first setup
      
    dayjs 
    • Day notes
      
    semver 
    • Application should start.
      
    https-proxy-agent ???  
    sax 
    • EverNote import
      
    ini 
    • Affects config, generally if the application starts then it should be OK.
      
    jsplumbRELATION_MAP
    • Relation map note type
      
    jquery.mark.es6MARKJS
    • In search, when highlighting the text that matched.
    • In search in HTML, which might not actually be used since it seems to have been replaced by CKEditor's own find & replace dialog.
      
    knockout.js 
    • Used in rendering the login and main layout of the application.
      
    normalize.min.css 
    • Used in shared notes.
      
    wheel-zoom.min.jsWHEEL_ZOOM
    • When opening a image that is in attachment.
    • When opening a stand-alone image note.
    • When zooming in a mermaid chart.
      
    fancytree 
    • The note tree should be fully functional.
      
    bootstrap 
    • Check mostly the on-boarding pages, when there is no database.
      
    electron-debug 
    • Run electron using npm run start-electron and check that the debug hotkeys are still working (Ctrl+Shift+I on Windows/Linux, Cmd+Alt+I for dev tools, Cmd/Ctrl+R for reload).
      
    electron-dl    
    eslint    
    marked 
    • Importing a markdown note.
     Yes
    force-graph 
    • Note map
      
    \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Dependencies/Per-dependency checks/bettersqlite binaries.md b/docs/Developer Guide/Developer Guide/Dependencies/Per-dependency checks/bettersqlite binaries.md new file mode 100644 index 000000000..5a473b5e5 --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Dependencies/Per-dependency checks/bettersqlite binaries.md @@ -0,0 +1,25 @@ +# bettersqlite binaries +### The native node bindings + +`better-sqlite3` has native Node bindings. With updates of `better-sqlite3`, but also of Electron and Node.js versions, these bindings need to be updated. + +Note that Electron and Node.js versions need different versions of these bindings, since Electron usually packs a different version of Node.js. + +During development, `pnpm install` tries to build or reuse prebuilt natives for the current Node.js version. This makes `npm run start-server` work out of the box. Trying to run `npm run start-electron` with these versions generally causes an error such as this: + +``` +Uncaught Exception: +Error: The module '/Users/elian/Projects/Notes/node_modules/better-sqlite3/build/Release/better_sqlite3.node' +was compiled against a different Node.js version using +NODE_MODULE_VERSION 108. This version of Node.js requires +NODE_MODULE_VERSION 116. Please try re-compiling or re-installing +the module (for instance, using `npm rebuild` or `npm install`). +``` + +### How the natives are handled + +To avoid issues between the `server` and the `desktop`, the `desktop` build gets its own copy of the `bettersqlite3` dependency in its `node_module`. This copy is then rebuilt automatically to match the Electron version. + +This process of rebuilding is handled by `scripts/electron-rebuild.mts` which runs automatically after `pnpm install` (via `postinstall`). + +If needed, the script can be run manually again via `pnpm postinstall`. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Documentation.md b/docs/Developer Guide/Developer Guide/Documentation.md similarity index 66% rename from docs/Developer Guide/Developer Guide/Old documentation/Documentation.md rename to docs/Developer Guide/Developer Guide/Documentation.md index 987582cac..c11d3164c 100644 --- a/docs/Developer Guide/Developer Guide/Old documentation/Documentation.md +++ b/docs/Developer Guide/Developer Guide/Documentation.md @@ -1,29 +1,32 @@ # Documentation -
    - -There are multiple types of documentation for Trilium: +There are multiple types of documentation for Trilium: * The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing F1. * The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers. * _Release Notes_, this contains the change log for each released or soon-to-be-released version. The release notes are used automatically by the CI when releasing a version. * The _Script API_, which is an automatically generated documentation for the front-end and back-end APIs for scripts. -## Editing documentation +## Location of the documentation + +All documentation is stored in the [Trilium](https://github.com/TriliumNext/Trilium) repository: + +* `docs/Developer Guide` contains Markdown documentation that can be modified either externally (using a Markdown editor, or internally using Trilium). +* `docs/Release Notes` is also stored in Markdown format and can be freely edited. +* `docs/Script API` contains auto-generated files and thus must not be modified. +* `docs/User Guide` contains also Markdown-only documentation but must generally not be edited externally. + * The reason is that the `pnpm edit-docs:edit-docs` feature will not only import/export this documentation, but also generate the corresponding HTML documentation and meta structure in `src/public/app/doc_notes/en/User Guide`. + * It's theoretically possible to edit the Markdown files externally and then run `docs:edit` and trigger a change in order to build the documentation, but that would not be a very productive workflow. + +## Editing the documentation There are two ways to modify documentation: * Using a special mode of Trilium. * By manually editing the files. -### Using `docs:edit` +### Using the `edit-docs` app -To edit the documentation using Trilium, set up a working development environment and run the following commands: - -* On most operating systems, `npm run electron:switch` followed by `npm run docs:edit` -* On NixOS, `npm run docs:edit-nix`. - -> [!NOTE] -> `npm run docs:edit` acts very similar to `npm run electron:start` in the sense that you cannot both be editing documentation and starting a server. Using both `npm run electron:start` and `docs:edit` is possible, since they are using the same Electron instance. +To edit the documentation using Trilium, set up a working development environment via Environment Setup and run the following command: `pnpm edit-docs:edit-docs`. How it works: @@ -50,24 +53,30 @@ Important aspects to consider: * The Trilium import/export mechanism is not perfect, so if you make some modifications to the documentation using `docs:edit`, at the next import/export/import cycle some whitespace might get thrown in. It's generally safe to commit the changes as-is. * Since we are importing Markdown, editing HTML and then exporting the HTML back to Markdown there might be some edge cases where the formatting is not properly preserved. Try to identify such cases and report them in order to get them fixed (this will benefit also the users). -## Location of the documentation +## Automation -All documentation is stored in the [Notes](https://github.com/TriliumNext/Trilium) repository: +The documentation is built via `apps/build-docs`: -* `docs/Developer Guide` contains Markdown documentation that can be modified either externally (using a Markdown editor, or internally using Trilium). -* `docs/Release Notes` is also stored in Markdown format and can be freely edited. -* `docs/Script API` contains auto-generated files and thus must not be modified. -* `docs/User Guide` contains also Markdown-only documentation but must generally not be edited externally. - * The reason is that the `docs:edit` feature will not only import/export this documentation, but also generate the corresponding HTML documentation and meta structure in `src/public/app/doc_notes/en/User Guide`. - * It's theoretically possible to edit the Markdown files externally and then run `docs:edit` and trigger a change in order to build the documentation, but that would not be a very productive workflow. +1. The output directory is cleared. +2. The User Guide and the Developer Guide are built. + 1. The documentation from the repo is archived and imported into an in-memory instance. + 2. The documentation is exported using the shared theme. +3. The API docs (internal and ETAPI) are statically rendered via Redocly. +4. The script API is generated via `typedoc` + +The `deploy-docs` workflow triggers the documentation build and uploads it to CloudFlare Pages. ## Updating the Script API As mentioned previously, the Script API is not manually editable since it is auto-generated using TypeDoc. -To update the API documentation, simply run `npm run docs:build`. Compare the changes (if any) and commit them. +To update the API documentation, simply run `pnpm docs:build`. Compare the changes (if any) and commit them. -Note that in order to simulate the environment a script would have, some fake source files (in the sense that they are only used for documentation) are being used as entrypoints for the documentation: +Note that in order to simulate the environment a script would have, some fake source files (in the sense that they are only used for documentation) are being used as entrypoints for the documentation. Look for `backend_script_entrypoint` and `frontend_script_entrypoint` in `apps/build-docs/src`. -* For back-end scripts, the script is located in `src/services/backend_script_entrypoint.ts`. -* For front-end scripts, the script is located in `src/public/app/services/frontend_script_entrypoint.ts`. \ No newline at end of file +## Building locally + +In the Git root: + +* Run `pnpm docs:build`. The built documentation will be available in `site` at Git root. +* To also run a webserver to test it, run `pnpm docs:preview` (this will not build the documentation) and navigate to `localhost:9000`. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Documentation/Documentation references in th.md b/docs/Developer Guide/Developer Guide/Documentation/Documentation references in th.md similarity index 69% rename from docs/Developer Guide/Developer Guide/Old documentation/Documentation/Documentation references in th.md rename to docs/Developer Guide/Developer Guide/Documentation/Documentation references in th.md index 1c9a9fea9..79c1bd80e 100644 --- a/docs/Developer Guide/Developer Guide/Old documentation/Documentation/Documentation references in th.md +++ b/docs/Developer Guide/Developer Guide/Documentation/Documentation references in th.md @@ -13,6 +13,8 @@ https://triliumnext.github.io/Docs/Wiki/ There is a pattern of “?” buttons throughout the application which make use of the `data-help-page` attribute. Whenever these buttons are pressed, the user is redirected to the corresponding wiki page by prepending the wiki root URL to the `data-help-page` attribute. +### Deprecated `help-page` attribute + Since the current wiki has a different structure than the original, for example to link to [https://github.com/TriliumNext/Docs/blob/main/Wiki/tree-concepts.md](https://github.com/TriliumNext/Docs/blob/main/Wiki/tree-concepts.md) the `data-help-page` attribute must be set to `tree-concepts.md`. For links to headings, simply add the heading after the `.md`: `tree-concepts.md#prefix` @@ -20,4 +22,12 @@ For links to headings, simply add the heading after the `.md`: `tree-concepts.md You can identify those by looking for: * `.attr("data-help-page"` -* `data-help-page="` \ No newline at end of file +* `data-help-page="` + +### More modern `data-in-app-help` attribute + +Instead of opening in a web browser, this opens the help directly in the application in a split view. This is handled via the `data-in-app-help` attribute, where the value is the note ID of the help page without the `_help_` prefix. + +### React + +Use the `HelpButton` component in the same fashion as the `data-in-app-help` attribute. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Environment Setup.md b/docs/Developer Guide/Developer Guide/Environment Setup.md index 95d14cd50..bf7f44adb 100644 --- a/docs/Developer Guide/Developer Guide/Environment Setup.md +++ b/docs/Developer Guide/Developer Guide/Environment Setup.md @@ -33,4 +33,4 @@ Run `pnpm i` at the top of the `Notes` repository to install the dependencies. Our recommended IDE for working on Trilium is Visual Studio Code (or VSCodium if you are looking for a fully open-source alternative). -By default we include a number of suggested extensions which should appear when opening the repository in VS Code. Most of the extensions are for integrating various technologies we are using such as Playwright and Vitest for testing or for Internationalisation / Translations. \ No newline at end of file +By default we include a number of suggested extensions which should appear when opening the repository in VS Code. Most of the extensions are for integrating various technologies we are using such as Playwright and Vitest for testing or for Internationalisation / Translations. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Documentation_image.png b/docs/Developer Guide/Developer Guide/Old documentation/Documentation_image.png deleted file mode 100644 index 542bb7858..000000000 Binary files a/docs/Developer Guide/Developer Guide/Old documentation/Documentation_image.png and /dev/null differ diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Installation/Download latest nightly and in.md b/docs/Developer Guide/Developer Guide/Old documentation/Installation/Download latest nightly and in.md deleted file mode 100644 index 0d5f2a2e4..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Installation/Download latest nightly and in.md +++ /dev/null @@ -1,12 +0,0 @@ -# Download latest nightly and install it -On Ubuntu: - -``` -#!/usr/bin/env bash - -name=TriliumNotes-linux-x64-nightly.deb -rm -f $name* -wget https://github.com/TriliumNext/Trilium/releases/download/nightly/$name -sudo apt-get install ./$name -rm $name -``` \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Project maintenance/Updating dependencies/bettersqlite binaries.md b/docs/Developer Guide/Developer Guide/Old documentation/Project maintenance/Updating dependencies/bettersqlite binaries.md deleted file mode 100644 index 5538646ca..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Project maintenance/Updating dependencies/bettersqlite binaries.md +++ /dev/null @@ -1,41 +0,0 @@ -# bettersqlite binaries -### The native node bindings - -`better-sqlite3` has native Node bindings. With updates of `better-sqlite3`, but also of Electron and Node.js versions, these bindings need to be updated. - -Note that Electron and Node.js versions need different versions of these bindings, since Electron usually packs a different version of Node.js. - -During development, `npm install` tries to build or reuse prebuilt natives for the current Node.js version. This makes `npm run start-server` work out of the box. Trying to run `npm run start-electron` with these versions generally causes an error such as this: - -``` -Uncaught Exception: -Error: The module '/Users/elian/Projects/Notes/node_modules/better-sqlite3/build/Release/better_sqlite3.node' -was compiled against a different Node.js version using -NODE_MODULE_VERSION 108. This version of Node.js requires -NODE_MODULE_VERSION 116. Please try re-compiling or re-installing -the module (for instance, using `npm rebuild` or `npm install`). -``` - -### How the natives are handled - -Locally, this can be fixed by rebuilding the binaries, which is what `npm run switch-electron` does, which uses `electron-rebuild` under the hood. - -When the deliveries are built (see Build deliveries locally), it is not feasible to rebuild the dependencies since we are building for multiple platforms. Luckily, `better-sqlite3` provides these prebuilt binaries from us, available as artifacts on [their GitHub releases page](https://github.com/WiseLibs/better-sqlite3/releases/).  - -The build script manages the natives for `better-sqlite3` by keeping a copy of the `.node` file for every platform in `bin/better-sqlite3`. - -Whenever the version of `better-sqlite3` changes, the `.node` files must also be renewed based on their releases page. To simplify this process, a script was created in `bin/better-sqlite3/update.sh`. - -## How to update the natives - -The update script needs to know the version of Electron or Node.js for which to download the prebuilt binaries. - -If you get errors during download, check on the [releases page](https://github.com/WiseLibs/better-sqlite3/releases/) to ensure that this particular combination of Electron/Node actually exists for the given release. - -To determine the `NODE_MODULE_VERSION` that is required, look for `This version of Node.js requires` -`NODE_MODULE_VERSION` in the error when starting Trilium via: - -* `npm run start-electron` (or run any Electron [delivery](../../../Building/Build%20deliveries%20locally.md)), case in which the `ELECTRON_VERSION` variable needs to be changed. -* `npm run start-server` (or run the Linux server delivery), case in which the `NODE_VERSION` variable needs to be changed. - -Check which files got changed after running the update script and for each platform that got changed, test it locally via Build deliveries locally or via the CI. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Releasing a version.md b/docs/Developer Guide/Developer Guide/Old documentation/Releasing a version.md deleted file mode 100644 index ed3706f7e..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Releasing a version.md +++ /dev/null @@ -1,22 +0,0 @@ -# Releasing a version -On NixOS: - -``` -nix-shell -p dpkg fakeroot jq nodejs_20 -``` - -Then simply run from project root: - -``` -./bin/release.sh 1.2.3 -``` - -where `1.2.3` is the desired release version. - -If a version ends with `-beta`, it will automatically be marked as pre-release in GitHub. - -This will automatically generate a release in GitHub if everything goes according to plan. - -Note that the Windows installer is not automatically uploaded yet, it has to be taken from the [main workflow of the CI from the `develop` branch](../Architecture/CI/Main.md). - -Make sure to check test the artifacts of the release. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Scripting/Server-side imports.md b/docs/Developer Guide/Developer Guide/Old documentation/Scripting/Server-side imports.md deleted file mode 100644 index c19366cee..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Scripting/Server-side imports.md +++ /dev/null @@ -1,16 +0,0 @@ -# Server-side imports -Trilium Notes allowed the use of Common.js module imports inside backend scripts, such as: - -``` -const isBetween = require('dayjs/plugin/isBetween') -api.dayjs.extend(isBetween) -``` - -For TriliumNext, the backend has been switched to use ESM which has a slightly more complicated syntax. Instead of `require` we now have `import` but which is asynchronous so it will require an `await`: - -``` -const isBetween = (await import("dayjs/plugin/isBetween")).default; -api.dayjs.extend(isBetween); -``` - -Note that `.default` is also usually needed to obtain the same behaviour as a CJS import. When in doubt, use `console.log` to see the output of the value returned by `await import`. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Scripting/Widgets.md b/docs/Developer Guide/Developer Guide/Old documentation/Scripting/Widgets.md deleted file mode 100644 index 57de0ad15..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Scripting/Widgets.md +++ /dev/null @@ -1,33 +0,0 @@ -# Widgets -To create a basic widget, simply create a code note with type “JS frontend”. Add the `#widget` label in order for it to be loaded at startup. - -``` -const template = `
    `; - -class MyWidget extends api.BasicWidget { - get position() { return 1; } - get parentWidget() { return "left-pane" } - - doRender() { - this.$widget = $(template); - return this.$widget; - } -} - -module.exports = new MyWidget(); -``` - -`parentWidget()` can be given the following values: - -* `left-pane` - This renders the widget on the left side of the screen where the note tree lives. -* `center-pane` - This renders the widget in the center of the layout in the same location that notes and splits appear. -* `note-detail-pane` - This renders the widget _with_ the note in the center pane. This means it can appear multiple times with splits. -* `right-pane` - This renders the widget to the right of any opened notes. - -* * * - -Reference: - -* [https://trilium.rocks/X7pxYpiu0lgU](https://trilium.rocks/X7pxYpiu0lgU) -* [https://github.com/zadam/trilium/wiki/Widget-Basics](https://github.com/zadam/trilium/wiki/Widget-Basics) -* [https://github.com/zadam/trilium/wiki/Frontend-Basics](https://github.com/zadam/trilium/wiki/Frontend-Basics) \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Building the editor.md b/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Building the editor.md deleted file mode 100644 index 940617026..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Building the editor.md +++ /dev/null @@ -1,21 +0,0 @@ -# Building the editor -First, make sure Environment setup is set up. - -## Trigger the build - -``` -cd packages/ckeditor5-build-trilium -yarn build -``` - -This will trigger a change in the `build` directory. - -## Copy the build artifact to the main repo - -Go to `packages/ckeditor5-build-balloon-trilium/build` and copy `ckeditor.js` and `ckeditor.js.map` to `libraries/ckeditor` in the `Notes` repository. - -An example shell command to copy it: - -``` -cp build/ckeditor.* ~/Projects/TriliumNext/Notes/libraries/ckeditor/ -``` \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Environment setup.md b/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Environment setup.md deleted file mode 100644 index 76819a12b..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Environment setup.md +++ /dev/null @@ -1,26 +0,0 @@ -# Environment setup -## Clone the repository - -To set up the repository: - -``` -git clone https://github.com/TriliumNext/trilium-ckeditor5.git -``` - -## Install dependencies - -First, install root dependencies: - -``` -cd trilium-ckeditor5 -yarn install -``` - -Secondly, install the Trilium build dependencies: - -``` -cd packages/ckeditor5-build-trilium -yarn install -``` - -To trigger the build, see Building the editor. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Updating to a newer version of.md b/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Updating to a newer version of.md deleted file mode 100644 index 6e7808f67..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Updating to a newer version of.md +++ /dev/null @@ -1,65 +0,0 @@ -# Updating to a newer version of CKEditor -## Before updating - -Make sure that all the plugins are compatible with this version:  Versions and external plugins. If not, they will need to be updated to the same version as the one you are updating, by altering their `package.json`. - -If the plugin is external to the Trilium organisation, it needs to be forked first. - -## Environment setup - -The first step is to add the CKEditor source as a remote. This only needs to be done once. - -``` -git remote add upstream ssh://git@github.com/ckeditor/ckeditor5.git -git fetch upstream -``` - -## Update steps - -Due to how the repository is structured, updates to the CKEditor are a bit difficult. - -1. `git fetch upstream` -2. Pick a version and merge with it: `git merge -X theirs v99.2.0` -3. When there are complicated conflicts, sometimes it's easier to take everything from the target version instead, for a given path: `git checkout v99.2.0 -- "packages/ckeditor5-list/**"`. -4. Go in `packages/ckeditor5-build-trilium/package.json` and run `node sync-version.js` to update the `package.json` with the new versions. Review and commit the change. -5. Follow again the dependency setup in Environment setup, as they have changed. -6. [Run the build](Building%20the%20editor.md) and check that it works. - -## Final steps - -1. Start the TriliumNext server -2. If updated to a newer version of CKEditor, check type `CKEDITOR_VERSION` in the browser/Electron console to ensure that the correct version is used. -3. Do a basic sanity check as well. -4. Commit and push the change on both sides (in the `trilium-ckeditor5` repo and in the `Notes` repo). - -## Troubleshooting client side errors - -These errors might show up when testing the Trilium app: - -``` -ReferenceError: CKEditor is not defined -``` - -Usually this is a side effect of another error, check the logs carefully to see if there is any other related error (perhaps a `CKEditorError`). - -* * * - -``` -Uncaught error: Message: CKEditorError: ckeditor-duplicated-modules -``` - -Most likely cause is one of the external plugins is incompatible with this version. - -For example, to disable the Math plugin, go to `packages/ckeditor5-build-trilium/src/config.ts` and modify: - -```diff --import Math from '@triliumnext/ckeditor5-math/src/math'; --import AutoformatMath from '@triliumnext/ckeditor5-math/src/autoformatmath'; - -export const COMMON_PLUGINS = [ -- Math, -- AutoformatMath, -] -``` - -In this case, make sure to align the version of all the external plugins with the one you are updating to, usually by forking the external plugin and updating its versions. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Versions and external plugins.md b/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Versions and external plugins.md deleted file mode 100644 index 2fe124c31..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/CKEditor/Versions and external plugins.md +++ /dev/null @@ -1,8 +0,0 @@ -# Versions and external plugins -## External plugins - -| | | | -| --- | --- | --- | -| trilium-ckeditor5 | 43.2.0 | | -| `ckeditor5-math` | | See ckeditor5-math. | -| | | | \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/ckeditor5-math.md b/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/ckeditor5-math.md deleted file mode 100644 index 91b6b265f..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/ckeditor5-math.md +++ /dev/null @@ -1,29 +0,0 @@ -# ckeditor5-math -
    ckeditor5-math in action.
    - -A fork of [isaul32/ckeditor5-math](https://github.com/isaul32/ckeditor5-math), which is the CKEditor5 plugin which adds the math functionality. The fork was created to handle #297: Insert Math appears to be broken. - -## Development environment - -* Tested on Node.js 20. -* The package manager is yarn 1 (v1.22.22 is known to be working fine for it at the time of writing). - -Important commands: - -* To check if the code has any formatting issues: `yarn lint` -* To start a live preview: `yarn start` -* To run the tests: `yarn test` - * Note that this requires Chromium, on NixOS this can be achieved by running a `nix-shell -p chromium`, and running `CHROME_BIN=$(which chromium) yarn test` inside it. - -## 📦 Packages - -The built artifact of the plugin is released by the CI and available on the [GitHub NPM registry](https://github.com/TriliumNext/ckeditor5-math/pkgs/npm/ckeditor5-math). - -Note that due to limitations on GitHub's registry, it is not possible to install this package without setting up a personal access token (even though the package itself is public). See [missing note] for more information. - -## ⬆️ Integrating with CKEditor - -1. Release a new version: Release management & continuous integration -2. In `trilium-ckeditor5`, go to `packages/ckeditor5-build-trilium/package.json` in the CKEditor repository and change the dependency of `@triliumnext/ckeditor5-math` to the newly released version. -3. Run `yarn install`. -4. Proceed with Building the editor to integrate everything into TriliumNext and then commit the change. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/ckeditor5-math/Release management & continuou.md b/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/ckeditor5-math/Release management & continuou.md deleted file mode 100644 index 1511f4bfc..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/ckeditor5-math/Release management & continuou.md +++ /dev/null @@ -1,16 +0,0 @@ -# Release management & continuous integration -To automate the release process, a GitHub workflow has been added which builds the package and releases it over to GitHub NPM registry. - -The workflow publishes a release whenever a tag with the correct format is pushed. - -The steps are as follows: - -1. Ensure that the source code is clean and ready for a release. -2. Go to `package.json` and bump the `version` field. -3. Commit the changes. -4. Tag the commit with `v1.2.3`, with the correct version number. -5. Push the changes. - -Then follow the CI and it should indicate success. Afterwards, check the [package](https://github.com/TriliumNext/ckeditor5-math/pkgs/npm/ckeditor5-math)section to ensure that the package is in the “Recent Versions” section. - -If the changes could benefit upstream, consider opening a pull request with the changes there as well. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/ckeditor5-math/Updating with upstream.md b/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/ckeditor5-math/Updating with upstream.md deleted file mode 100644 index b69003358..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Sub-projects/ckeditor5-math/Updating with upstream.md +++ /dev/null @@ -1,21 +0,0 @@ -# Updating with upstream -If there was a change in the upstream repository ([isaul32/ckeditor5-math](https://github.com/isaul32/ckeditor5-math)), it can be integrated as follows: - -1. Add the upstream as remote (`git remote add upstream ssh://git@github.com/isaul32/ckeditor5-math.git`). -2. Fetch the changes: `git fetch upstream` -3. Merge with a tag: `git merge v43.1.2` -4. Solve the conflict in `package.json` by: - 1. Taking the same version as the upcoming one and appending `-hotfix1`. - 2. Keeping the `@triliumnext/ckeditor5-math` name. -5. Install dependencies: `yarn install` -6. Check that the build works via `yarn prepublishOnly`. -7. Commit the changes, push them. -8. Release a version with Release management & continuous integration. - -## CI job not triggered after pushing all the upstream tags - -If the CI job was not triggered, you might have accidentally pushed a lot of tags using `git push --tags`. Manually delete the tag and push it again: - -```diff -git push -d origin v43.1.2-hotfix1 && git push --tags -``` \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/1_Setting up authentication_.png b/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/1_Setting up authentication_.png deleted file mode 100644 index 020472c6d..000000000 Binary files a/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/1_Setting up authentication_.png and /dev/null differ diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/Running tests.md b/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/Running tests.md deleted file mode 100644 index 3ab98a39c..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/Running tests.md +++ /dev/null @@ -1,38 +0,0 @@ -# Running tests -## First-time run - -Before starting Playwright, it has to be installed locally via: - -``` -npx playwright install -``` - -## Starting the integration test server - -There are two types of integration test servers: - -* `npm run integration-mem-db` will run a server with dev mode disabled. - * This is usually what the end user will see when accessing a server instance. - * It will not test the Electron/desktop side of the application. - * Changes to the public scripts will not take effect until running `npm run webpack`. -* `npm run integration-mem-db-dev` will run a server with dev mode enabled. - * This is usually what a dev sees when running `npm run start-server`. - * The difference with the production one is that the assets are loaded directly from files and as such it does not require `npm run webpack` to see changes. - -Either options will open up a server on [localhost:8082](http://localhost:8082) that can be accessed either manually via the browser or via Playwright. - -When asked for a password, the password is `demo1234`. - -## Starting the interactive test runner - -After starting the integration test server, to run the Playwright UI, run in the terminal: - -``` -npx playwright test --ui -``` - -It is also possible to run the interactive code generator instead: - -``` -npx playwright codegen -``` \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/Setting up authentication.md b/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/Setting up authentication.md deleted file mode 100644 index 4df7880fe..000000000 --- a/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/Setting up authentication.md +++ /dev/null @@ -1,12 +0,0 @@ -# Setting up authentication -There is a setup test that stores the authentication token so that it can be reused throughout all the tests. - -If tests fail due to being stuck on login, then it must be run. - -To run it manually press “all” near the “Status:” text on top-left of the window - -
    - -Then check “setup” and look for `auth.setup.ts` and press its corresponding Run button: - -
    \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/Setting up authentication_.png b/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/Setting up authentication_.png deleted file mode 100644 index 4b260dfbc..000000000 Binary files a/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/Setting up authentication_.png and /dev/null differ diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Testing.md b/docs/Developer Guide/Developer Guide/Testing.md similarity index 54% rename from docs/Developer Guide/Developer Guide/Old documentation/Testing.md rename to docs/Developer Guide/Developer Guide/Testing.md index 95efd9919..570f52ded 100644 --- a/docs/Developer Guide/Developer Guide/Old documentation/Testing.md +++ b/docs/Developer Guide/Developer Guide/Testing.md @@ -1,4 +1,48 @@ # Testing +### Test Organization + +**Parallel Tests** (can run simultaneously): + +* Client tests +* Package tests +* E2E tests (isolated databases) + +**Sequential Tests** (shared resources): + +* Server tests (shared database) +* CKEditor plugin tests + +### Test Frameworks + +* **Vitest** - Unit and integration tests +* **Playwright** - E2E tests +* **Happy-DOM** - DOM testing environment + +## Test locations + +``` +apps/ +├── server/ +│ └── src/**/*.spec.ts # Server tests +├── client/ +│ └── src/**/*.spec.ts # Client tests +└── server-e2e/ +│ └── tests/**/*.spec.ts # E2E tests +└── desktop/ + └── e2e + └── tests/**/*.spec.ts # E2E tests +``` + +## Running tests + +At project root: + +``` +pnpm test:all # All tests +pnpm test:parallel # Fast parallel tests +pnpm test:sequential # Sequential tests only +``` + ## Unit testing and integration testing Using `vitest`, there are some unit and integration tests done for both the client and the server. @@ -17,17 +61,14 @@ Note that some integration tests rely on an in-memory database in order to funct ### REST API testing for the server -Some original work was done by Zadam in `/test-etapi`, using `.http` files. - -New effort using `vitest` and `supertest` to initialize the Express server and run assertions without having to make actual requests to the server. +API tests are handled via `vitest` and `supertest` to initialize the Express server and run assertions without having to make actual requests to the server. An important aspect is that we have access to the Express `app` which allows for interesting assertions such as checking the state of the server, registering debug middleware and so on. -One example is `src/share/routes.spec.ts`. +One example is `src/share/routes.spec.ts`, or for the ETAPI in `apps/server/spec/etapi`. These integration tests are run alongside unit tests. ## End-to-end testing -* This tests both the client and the server, by running the server and then using Playwright to query the state of the page. -* These can be found in `/e2e`. \ No newline at end of file +See End-to-end tests. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Testing/End-to-end tests.md b/docs/Developer Guide/Developer Guide/Testing/End-to-end tests.md new file mode 100644 index 000000000..60060adae --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Testing/End-to-end tests.md @@ -0,0 +1,40 @@ +# End-to-end tests +**Server E2E:** + +* Tests the entire ETAPI. +* Tests WebSocket functionality + +**Desktop E2E:** + +* Playwright with Electron +* Tests some basic functionality such as creating a new document. + +These can be found in `apps/server-e2e` and `apps/desktop/e2e`. + +## First-time run + +Before starting Playwright, it has to be installed locally via: + +``` +pnpm playwright install +``` + +## Starting the integration test server + +Simply run `pnpm e2e` in one of the e2e projects. + +The integration server doesn't have authentication enabled to avoid login issues. + +## Starting the interactive test runner + +After starting the integration test server, to run the Playwright UI, run in the terminal: + +``` +pnpm playwright test --ui +``` + +It is also possible to run the interactive code generator instead: + +``` +pnpm playwright codegen +``` \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Testing/Integration testing.md b/docs/Developer Guide/Developer Guide/Testing/Integration testing.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/Test database.md b/docs/Developer Guide/Developer Guide/Testing/Test database.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Old documentation/Testing/Integration testing/Test database.md rename to docs/Developer Guide/Developer Guide/Testing/Test database.md diff --git a/docs/Developer Guide/Developer Guide/Testing/Unit tests.md b/docs/Developer Guide/Developer Guide/Testing/Unit tests.md new file mode 100644 index 000000000..a009b8d92 --- /dev/null +++ b/docs/Developer Guide/Developer Guide/Testing/Unit tests.md @@ -0,0 +1,7 @@ +# Unit tests +At project level: + +* `pnpm server:test` +* `pnpm client:test` + +Unit tests are stored in the same directory as the source code being tested, with the `.spec.ts` suffix. \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Troubleshooting/Error [TransformError] The pac.md b/docs/Developer Guide/Developer Guide/Troubleshooting/Error [TransformError] The pac.md similarity index 99% rename from docs/Developer Guide/Developer Guide/Old documentation/Troubleshooting/Error [TransformError] The pac.md rename to docs/Developer Guide/Developer Guide/Troubleshooting/Error [TransformError] The pac.md index 8a93a52be..82a5d93a8 100644 --- a/docs/Developer Guide/Developer Guide/Old documentation/Troubleshooting/Error [TransformError] The pac.md +++ b/docs/Developer Guide/Developer Guide/Troubleshooting/Error [TransformError] The pac.md @@ -36,5 +36,5 @@ The solution is to remove `node_modules` and reinstall all dependencies: ``` rm -r node_modules -npm install +pnpm install ``` \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index be65024ee..ea2fdd378 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,17 @@ -# Trilium Notes +# Trilium Notes Documentation + +## 📚 Technical Documentation + +**NEW:** Comprehensive technical and architectural documentation is now available! + +- **[Technical Documentation Index](TECHNICAL_DOCUMENTATION.md)** - Complete index to all technical docs +- **[Architecture Overview](ARCHITECTURE.md)** - System design and core patterns +- **[Database Architecture](DATABASE.md)** - Complete database documentation +- **[Synchronization](SYNCHRONIZATION.md)** - Sync protocol and implementation +- **[Scripting System](SCRIPTING.md)** - User scripting guide and API +- **[Security Architecture](SECURITY_ARCHITECTURE.md)** - Security implementation details + +## 📖 User Documentation Please see the [main documentation](index.md) or visit one of our translated versions: @@ -9,4 +22,11 @@ Please see the [main documentation](index.md) or visit one of our translated ver - [简体中文](README-ZH_CN.md) - [繁體中文](README-ZH_TW.md) +## 🔧 Developer Documentation + +- [Developer Guide](Developer%20Guide/Developer%20Guide/) - Development environment and contribution guide +- [Script API](Script%20API/) - Complete scripting API reference + +## 🔗 Additional Resources + For the full application README, please visit our [GitHub repository](https://github.com/triliumnext/trilium). \ No newline at end of file diff --git a/docs/User Guide/!!!meta.json b/docs/User Guide/!!!meta.json index ee9df7820..c046fac03 100644 --- a/docs/User Guide/!!!meta.json +++ b/docs/User Guide/!!!meta.json @@ -25,17 +25,59 @@ { "type": "relation", "name": "internalLink", - "value": "BFs8mudNFgCS", + "value": "gh7bpGYxajRS", "isInheritable": false, "position": 20 }, { "type": "relation", "name": "internalLink", - "value": "GTwFsgaA0lCt", + "value": "BFs8mudNFgCS", "isInheritable": false, "position": 30 }, + { + "type": "relation", + "name": "internalLink", + "value": "GTwFsgaA0lCt", + "isInheritable": false, + "position": 40 + }, + { + "type": "relation", + "name": "internalLink", + "value": "poXkQfguuA0U", + "isInheritable": false, + "position": 50 + }, + { + "type": "relation", + "name": "internalLink", + "value": "WOcw2SLH6tbX", + "isInheritable": false, + "position": 60 + }, + { + "type": "relation", + "name": "internalLink", + "value": "Q2z6av6JZVWm", + "isInheritable": false, + "position": 70 + }, + { + "type": "relation", + "name": "internalLink", + "value": "MEtfsqa5VwNi", + "isInheritable": false, + "position": 80 + }, + { + "type": "relation", + "name": "internalLink", + "value": "9qPsTWBorUhQ", + "isInheritable": false, + "position": 90 + }, { "type": "label", "name": "shareAlias", @@ -1166,6 +1208,22 @@ "dataFileName": "Multi-Factor Authentication.md", "attachments": [] }, + { + "isClone": true, + "noteId": "Un4wj2Mak2Ky", + "notePath": [ + "pOsGYCXsbNQG", + "Otzi9La2YAUX", + "WOcw2SLH6tbX", + "Un4wj2Mak2Ky" + ], + "title": "Nix flake", + "prefix": null, + "dataFileName": "Nix flake.clone.md", + "type": "text", + "format": "markdown", + "isExpanded": false + }, { "isClone": false, "noteId": "yeEaYqosGLSh", @@ -1256,22 +1314,6 @@ "format": "markdown", "dataFileName": "System Requirements.md", "attachments": [] - }, - { - "isClone": true, - "noteId": "Un4wj2Mak2Ky", - "notePath": [ - "pOsGYCXsbNQG", - "Otzi9La2YAUX", - "WOcw2SLH6tbX", - "Un4wj2Mak2Ky" - ], - "title": "Nix flake", - "prefix": null, - "dataFileName": "Nix flake.clone.md", - "type": "text", - "format": "markdown", - "isExpanded": false } ] }, @@ -14081,6 +14123,109 @@ "format": "markdown", "dataFileName": "Safe mode.md", "attachments": [] + }, + { + "isClone": false, + "noteId": "HAIOFBoYIIdO", + "notePath": [ + "pOsGYCXsbNQG", + "tC7s2alapj8V", + "HAIOFBoYIIdO" + ], + "title": "Nightly release", + "notePosition": 260, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "iconClass", + "value": "bx bx-moon", + "isInheritable": false, + "position": 30 + } + ], + "format": "markdown", + "dataFileName": "Nightly release.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "ZmT9ln8XJX2o", + "notePath": [ + "pOsGYCXsbNQG", + "tC7s2alapj8V", + "ZmT9ln8XJX2o" + ], + "title": "Read-only database", + "notePosition": 270, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "iconClass", + "value": "bx bx-book-reader", + "isInheritable": false, + "position": 30 + }, + { + "type": "label", + "name": "shareAlias", + "value": "read-only-db", + "isInheritable": false, + "position": 40 + }, + { + "type": "relation", + "name": "internalLink", + "value": "wy8So3yZZlH9", + "isInheritable": false, + "position": 50 + }, + { + "type": "relation", + "name": "internalLink", + "value": "R9pX4DGra2Vt", + "isInheritable": false, + "position": 60 + }, + { + "type": "relation", + "name": "internalLink", + "value": "Gzjqa934BdH4", + "isInheritable": false, + "position": 70 + }, + { + "type": "relation", + "name": "internalLink", + "value": "eIg8jdvaoNNd", + "isInheritable": false, + "position": 80 + }, + { + "type": "relation", + "name": "internalLink", + "value": "GTwFsgaA0lCt", + "isInheritable": false, + "position": 90 + }, + { + "type": "relation", + "name": "internalLink", + "value": "KSZ04uQ2D1St", + "isInheritable": false, + "position": 100 + } + ], + "format": "markdown", + "dataFileName": "Read-only database.md", + "attachments": [] } ] }, @@ -14118,6 +14263,13 @@ "value": "bx bx-bot", "isInheritable": false, "position": 30 + }, + { + "type": "relation", + "name": "internalLink", + "value": "xYmIYSP6wE3F", + "isInheritable": false, + "position": 40 } ], "format": "markdown", @@ -14589,21 +14741,21 @@ { "type": "relation", "name": "internalLink", - "value": "zEY4DaJG4YT5", + "value": "GLks18SNjxmC", "isInheritable": false, "position": 10 }, { "type": "relation", "name": "internalLink", - "value": "SynTBQiBsdYJ", + "value": "zEY4DaJG4YT5", "isInheritable": false, "position": 20 }, { "type": "relation", "name": "internalLink", - "value": "GLks18SNjxmC", + "value": "SynTBQiBsdYJ", "isInheritable": false, "position": 30 }, @@ -14617,152 +14769,238 @@ { "type": "label", "name": "iconClass", - "value": "bx bx-info-circle", + "value": "bx bx-window", "isInheritable": false, "position": 40 } ], "format": "markdown", "dataFileName": "Frontend Basics.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "es8OU2GuguFU", - "notePath": [ - "pOsGYCXsbNQG", - "CdNpE2pqjmI6", - "es8OU2GuguFU" - ], - "title": "Examples", - "notePosition": 50, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "examples", - "isInheritable": false, - "position": 20 - }, - { - "type": "label", - "name": "iconClass", - "value": "bx bx-code-alt", - "isInheritable": false, - "position": 30 - } - ], - "format": "markdown", "attachments": [], - "dirFileName": "Examples", + "dirFileName": "Frontend Basics", "children": [ { "isClone": false, - "noteId": "TjLYAo3JMO8X", + "noteId": "MgibgPcfeuGz", "notePath": [ "pOsGYCXsbNQG", "CdNpE2pqjmI6", - "es8OU2GuguFU", - "TjLYAo3JMO8X" + "yIhgI5H7A2Sm", + "MgibgPcfeuGz" ], - "title": "\"New Task\" launcher button", + "title": "Custom Widgets", "notePosition": 10, "prefix": null, "isExpanded": false, "type": "text", - "mime": "text/html", + "mime": "text/markdown", "attributes": [ { - "type": "relation", - "name": "internalLink", - "value": "xYjQUYhpbUEW", - "isInheritable": false, - "position": 10 - }, - { - "type": "relation", - "name": "internalLink", - "value": "xYmIYSP6wE3F", + "type": "label", + "name": "shareAlias", + "value": "custom-widget", "isInheritable": false, "position": 20 }, - { - "type": "relation", - "name": "internalLink", - "value": "6f9hih2hXXZk", - "isInheritable": false, - "position": 30 - }, - { - "type": "relation", - "name": "internalLink", - "value": "zEY4DaJG4YT5", - "isInheritable": false, - "position": 40 - }, - { - "type": "relation", - "name": "internalLink", - "value": "m1lbrzyKDaRB", - "isInheritable": false, - "position": 50 - }, - { - "type": "relation", - "name": "internalLink", - "value": "s8alTXmpFR61", - "isInheritable": false, - "position": 60 - }, - { - "type": "relation", - "name": "internalLink", - "value": "yIhgI5H7A2Sm", - "isInheritable": false, - "position": 70 - }, { "type": "label", "name": "iconClass", - "value": "bx bx-task", + "value": "bx bxs-widget", "isInheritable": false, - "position": 80 - }, - { - "type": "label", - "name": "shareAlias", - "value": "new-task-button", - "isInheritable": false, - "position": 90 + "position": 30 } ], "format": "markdown", - "dataFileName": "New Task launcher button.md", - "attachments": [ + "dataFileName": "Custom Widgets.md", + "attachments": [], + "dirFileName": "Custom Widgets", + "children": [ { - "attachmentId": "9C2JA6tdtRpN", - "title": "image.png", - "role": "image", - "mime": "image/png", - "position": 10, - "dataFileName": "New Task launcher button_i.png" + "isClone": false, + "noteId": "YNxAqkI5Kg1M", + "notePath": [ + "pOsGYCXsbNQG", + "CdNpE2pqjmI6", + "yIhgI5H7A2Sm", + "MgibgPcfeuGz", + "YNxAqkI5Kg1M" + ], + "title": "Word count widget", + "notePosition": 10, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "6tZeKvSHEUiB", + "isInheritable": false, + "position": 10 + }, + { + "type": "relation", + "name": "internalLink", + "value": "6f9hih2hXXZk", + "isInheritable": false, + "position": 20 + }, + { + "type": "relation", + "name": "internalLink", + "value": "s8alTXmpFR61", + "isInheritable": false, + "position": 30 + }, + { + "type": "label", + "name": "shareAlias", + "value": "word-count", + "isInheritable": false, + "position": 40 + } + ], + "format": "markdown", + "dataFileName": "Word count widget.md", + "attachments": [ + { + "attachmentId": "JhM9NWfebzPi", + "title": "image.png", + "role": "image", + "mime": "image/png", + "position": 10, + "dataFileName": "Word count widget_image.png" + } + ] + }, + { + "isClone": false, + "noteId": "SynTBQiBsdYJ", + "notePath": [ + "pOsGYCXsbNQG", + "CdNpE2pqjmI6", + "yIhgI5H7A2Sm", + "MgibgPcfeuGz", + "SynTBQiBsdYJ" + ], + "title": "Widget Basics", + "notePosition": 20, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/markdown", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "zEY4DaJG4YT5", + "isInheritable": false, + "position": 10 + }, + { + "type": "relation", + "name": "internalLink", + "value": "BFs8mudNFgCS", + "isInheritable": false, + "position": 20 + }, + { + "type": "relation", + "name": "internalLink", + "value": "GLks18SNjxmC", + "isInheritable": false, + "position": 30 + }, + { + "type": "relation", + "name": "internalLink", + "value": "s8alTXmpFR61", + "isInheritable": false, + "position": 40 + }, + { + "type": "label", + "name": "shareAlias", + "value": "widget-basics", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Widget Basics.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "M8IppdwVHSjG", + "notePath": [ + "pOsGYCXsbNQG", + "CdNpE2pqjmI6", + "yIhgI5H7A2Sm", + "MgibgPcfeuGz", + "M8IppdwVHSjG" + ], + "title": "Right pane widget", + "notePosition": 30, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "right-pane-widget", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Right pane widget.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "VqGQnnPGnqAU", + "notePath": [ + "pOsGYCXsbNQG", + "CdNpE2pqjmI6", + "yIhgI5H7A2Sm", + "MgibgPcfeuGz", + "VqGQnnPGnqAU" + ], + "title": "CSS", + "notePosition": 40, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "css", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "CSS.md", + "attachments": [] } ] }, { "isClone": false, - "noteId": "7kZPMD0uFwkH", + "noteId": "es8OU2GuguFU", "notePath": [ "pOsGYCXsbNQG", "CdNpE2pqjmI6", - "es8OU2GuguFU", - "7kZPMD0uFwkH" + "yIhgI5H7A2Sm", + "es8OU2GuguFU" ], - "title": "Downloading responses from Google Forms", + "title": "Examples", "notePosition": 20, "prefix": null, "isExpanded": false, @@ -14772,49 +15010,182 @@ { "type": "label", "name": "shareAlias", - "value": "responses-from-google-forms", + "value": "examples", "isInheritable": false, "position": 20 - } - ], - "format": "markdown", - "dataFileName": "Downloading responses from Goo.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "DL92EjAaXT26", - "notePath": [ - "pOsGYCXsbNQG", - "CdNpE2pqjmI6", - "es8OU2GuguFU", - "DL92EjAaXT26" - ], - "title": "Using promoted attributes to configure scripts", - "notePosition": 30, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/html", - "attributes": [ + }, { "type": "label", - "name": "shareAlias", - "value": "promoted-attributes-config", + "name": "iconClass", + "value": "bx bx-code-alt", "isInheritable": false, - "position": 20 + "position": 30 } ], "format": "markdown", - "dataFileName": "Using promoted attributes to c.md", - "attachments": [ + "attachments": [], + "dirFileName": "Examples", + "children": [ { - "attachmentId": "7P3jzVEa1mk7", - "title": "image.png", - "role": "image", - "mime": "image/png", - "position": 10, - "dataFileName": "Using promoted attributes .png" + "isClone": false, + "noteId": "TjLYAo3JMO8X", + "notePath": [ + "pOsGYCXsbNQG", + "CdNpE2pqjmI6", + "yIhgI5H7A2Sm", + "es8OU2GuguFU", + "TjLYAo3JMO8X" + ], + "title": "\"New Task\" launcher button", + "notePosition": 10, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "xYjQUYhpbUEW", + "isInheritable": false, + "position": 10 + }, + { + "type": "relation", + "name": "internalLink", + "value": "xYmIYSP6wE3F", + "isInheritable": false, + "position": 20 + }, + { + "type": "relation", + "name": "internalLink", + "value": "6f9hih2hXXZk", + "isInheritable": false, + "position": 30 + }, + { + "type": "relation", + "name": "internalLink", + "value": "zEY4DaJG4YT5", + "isInheritable": false, + "position": 40 + }, + { + "type": "relation", + "name": "internalLink", + "value": "yIhgI5H7A2Sm", + "isInheritable": false, + "position": 50 + }, + { + "type": "relation", + "name": "internalLink", + "value": "m1lbrzyKDaRB", + "isInheritable": false, + "position": 60 + }, + { + "type": "relation", + "name": "internalLink", + "value": "s8alTXmpFR61", + "isInheritable": false, + "position": 70 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-task", + "isInheritable": false, + "position": 80 + }, + { + "type": "label", + "name": "shareAlias", + "value": "new-task-button", + "isInheritable": false, + "position": 90 + } + ], + "format": "markdown", + "dataFileName": "New Task launcher button.md", + "attachments": [ + { + "attachmentId": "9C2JA6tdtRpN", + "title": "image.png", + "role": "image", + "mime": "image/png", + "position": 10, + "dataFileName": "New Task launcher button_i.png" + } + ] + }, + { + "isClone": false, + "noteId": "7kZPMD0uFwkH", + "notePath": [ + "pOsGYCXsbNQG", + "CdNpE2pqjmI6", + "yIhgI5H7A2Sm", + "es8OU2GuguFU", + "7kZPMD0uFwkH" + ], + "title": "Downloading responses from Google Forms", + "notePosition": 20, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "responses-from-google-forms", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Downloading responses from Goo.md", + "attachments": [] + }, + { + "isClone": false, + "noteId": "DL92EjAaXT26", + "notePath": [ + "pOsGYCXsbNQG", + "CdNpE2pqjmI6", + "yIhgI5H7A2Sm", + "es8OU2GuguFU", + "DL92EjAaXT26" + ], + "title": "Using promoted attributes to configure scripts", + "notePosition": 30, + "prefix": null, + "isExpanded": false, + "type": "text", + "mime": "text/html", + "attributes": [ + { + "type": "label", + "name": "shareAlias", + "value": "promoted-attributes-config", + "isInheritable": false, + "position": 20 + } + ], + "format": "markdown", + "dataFileName": "Using promoted attributes to c.md", + "attachments": [ + { + "attachmentId": "7P3jzVEa1mk7", + "title": "image.png", + "role": "image", + "mime": "image/png", + "position": 10, + "dataFileName": "Using promoted attributes .png" + } + ] } ] } @@ -14822,162 +15193,76 @@ }, { "isClone": false, - "noteId": "GPERMystNGTB", + "noteId": "SPirpZypehBG", "notePath": [ "pOsGYCXsbNQG", "CdNpE2pqjmI6", - "GPERMystNGTB" + "SPirpZypehBG" ], - "title": "Events", - "notePosition": 70, + "title": "Backend scripts", + "notePosition": 30, "prefix": null, "isExpanded": false, "type": "text", - "mime": "text/markdown", + "mime": "text/html", "attributes": [ { - "type": "relation", - "name": "internalLink", - "value": "CdNpE2pqjmI6", - "isInheritable": false, - "position": 10 - }, - { - "type": "relation", - "name": "internalLink", - "value": "c5xB8m4g2IY6", - "isInheritable": false, - "position": 20 - }, - { - "type": "relation", - "name": "internalLink", - "value": "zEY4DaJG4YT5", + "type": "label", + "name": "shareAlias", + "value": "backend-basics", "isInheritable": false, "position": 30 }, - { - "type": "label", - "name": "shareAlias", - "value": "events", - "isInheritable": false, - "position": 10 - }, { "type": "label", "name": "iconClass", - "value": "bx bx-rss", + "value": "bx bx-server", "isInheritable": false, - "position": 20 + "position": 40 } ], "format": "markdown", - "dataFileName": "Events.md", - "attachments": [] - }, - { - "isClone": false, - "noteId": "MgibgPcfeuGz", - "notePath": [ - "pOsGYCXsbNQG", - "CdNpE2pqjmI6", - "MgibgPcfeuGz" - ], - "title": "Custom Widgets", - "notePosition": 80, - "prefix": null, - "isExpanded": false, - "type": "text", - "mime": "text/markdown", - "attributes": [ - { - "type": "label", - "name": "shareAlias", - "value": "custom-widget", - "isInheritable": false, - "position": 20 - }, - { - "type": "label", - "name": "iconClass", - "value": "bx bxs-widget", - "isInheritable": false, - "position": 30 - } - ], - "format": "markdown", - "dataFileName": "Custom Widgets.md", "attachments": [], - "dirFileName": "Custom Widgets", + "dirFileName": "Backend scripts", "children": [ { "isClone": false, - "noteId": "YNxAqkI5Kg1M", + "noteId": "fZ2IGYFXjkEy", "notePath": [ "pOsGYCXsbNQG", "CdNpE2pqjmI6", - "MgibgPcfeuGz", - "YNxAqkI5Kg1M" + "SPirpZypehBG", + "fZ2IGYFXjkEy" ], - "title": "Word count widget", + "title": "Server-side imports", "notePosition": 10, "prefix": null, "isExpanded": false, "type": "text", "mime": "text/html", "attributes": [ - { - "type": "relation", - "name": "internalLink", - "value": "6tZeKvSHEUiB", - "isInheritable": false, - "position": 10 - }, - { - "type": "relation", - "name": "internalLink", - "value": "6f9hih2hXXZk", - "isInheritable": false, - "position": 20 - }, - { - "type": "relation", - "name": "internalLink", - "value": "s8alTXmpFR61", - "isInheritable": false, - "position": 30 - }, { "type": "label", "name": "shareAlias", - "value": "word-count", + "value": "server-imports", "isInheritable": false, - "position": 40 + "position": 20 } ], "format": "markdown", - "dataFileName": "Word count widget.md", - "attachments": [ - { - "attachmentId": "JhM9NWfebzPi", - "title": "image.png", - "role": "image", - "mime": "image/png", - "position": 10, - "dataFileName": "Word count widget_image.png" - } - ] + "dataFileName": "Server-side imports.md", + "attachments": [] }, { "isClone": false, - "noteId": "SynTBQiBsdYJ", + "noteId": "GPERMystNGTB", "notePath": [ "pOsGYCXsbNQG", "CdNpE2pqjmI6", - "MgibgPcfeuGz", - "SynTBQiBsdYJ" + "SPirpZypehBG", + "GPERMystNGTB" ], - "title": "Widget Basics", + "title": "Events", "notePosition": 20, "prefix": null, "isExpanded": false, @@ -14987,34 +15272,41 @@ { "type": "relation", "name": "internalLink", - "value": "zEY4DaJG4YT5", + "value": "CdNpE2pqjmI6", "isInheritable": false, "position": 10 }, { "type": "relation", "name": "internalLink", - "value": "BFs8mudNFgCS", + "value": "c5xB8m4g2IY6", "isInheritable": false, "position": 20 }, { "type": "relation", "name": "internalLink", - "value": "GLks18SNjxmC", + "value": "zEY4DaJG4YT5", "isInheritable": false, "position": 30 }, { "type": "label", "name": "shareAlias", - "value": "widget-basics", + "value": "events", + "isInheritable": false, + "position": 10 + }, + { + "type": "label", + "name": "iconClass", + "value": "bx bx-rss", "isInheritable": false, "position": 20 } ], "format": "markdown", - "dataFileName": "Widget Basics.md", + "dataFileName": "Events.md", "attachments": [] } ] @@ -15028,7 +15320,7 @@ "GLks18SNjxmC" ], "title": "Script API", - "notePosition": 90, + "notePosition": 100, "prefix": null, "isExpanded": false, "type": "text", @@ -15191,7 +15483,7 @@ "vElnKeDNPSVl" ], "title": "Logging", - "notePosition": 100, + "notePosition": 110, "prefix": null, "isExpanded": false, "type": "text", diff --git a/docs/User Guide/User Guide.md b/docs/User Guide/User Guide.md index 0225eeccc..3e5537135 100644 --- a/docs/User Guide/User Guide.md +++ b/docs/User Guide/User Guide.md @@ -1,13 +1,25 @@ # User Guide Trilium is an open-source solution for note-taking and organizing a personal knowledge base. Use it locally on your desktop, or sync it with your self-hosted server to keep your notes everywhere you go. -For a quick overview of the application, visit our website at [triliumnotes.org](https://triliumnotes.org/). - > [!TIP] > The same documentation can be accessed locally from within the Trilium Notes application by pressing F1. ## Getting started 1. See Quick Start. -2. Understand Notes. -3. Browse through Collections. \ No newline at end of file +2. Go through Basic Concepts and Features. +3. Understand Notes. +4. Browse through Collections. + +## Quick links + +* Desktop Installation +* Server Installation +* Frontend API or Backend API +* [ETAPI reference](User%20Guide/Advanced%20Usage/ETAPI%20\(REST%20API\)/API%20Reference.dat) + +## External links + +* The [Trilium Notes website](https://triliumnotes.org/), for a quick presentation of the application. +* [Developer Guide](https://docs.triliumnotes.org/developer-guide/), to understand the architecture and processes behind the development of Trilium Notes. +* [GitHub Repository (TriliumNext/Trilium)](https://github.com/TriliumNext/Trilium/) \ No newline at end of file diff --git a/docs/User Guide/User Guide/AI.md b/docs/User Guide/User Guide/AI.md index d17f454c3..f5818d915 100644 --- a/docs/User Guide/User Guide/AI.md +++ b/docs/User Guide/User Guide/AI.md @@ -21,7 +21,7 @@ You will then need to set up the AI “provider” that you wish to use to creat In the following example, we're going to use our self-hosted Ollama instance to create the embeddings for our Notes. You can see additional documentation about installing your own Ollama locally in Installing Ollama. -To see what embedding models Ollama has available, you can check out [this search](https://ollama.com/search?c=embedding)on their website, and then `pull` whichever one you want to try out. As of 4/15/25, my personal favorite is `mxbai-embed-large`. +To see what embedding models Ollama has available, you can check out [this search](https://ollama.com/search?c=embedding) on their website, and then `pull` whichever one you want to try out. A popular choice is `mxbai-embed-large`. First, we'll need to select the Ollama provider from the tabs of providers, then we will enter in the Base URL for our Ollama. Since our Ollama is running on our local machine, our Base URL is `http://localhost:11434`. We will then hit the “refresh” button to have it fetch our models: @@ -80,10 +80,10 @@ You don't need to tell the LLM to execute a certain tool, it should “smartly ## Overview -Now that you know about embeddings and tools, you can just go ahead and use the “Chat with Notes” button, where you can go ahead and start chatting!: +To start, simply press the _Chat with Notes_ button in the Launch Bar.
    -If you don't see the “Chat with Notes” button on your side launchbar, you might need to move it from the “Available Launchers” section to the “Visible Launchers” section: +If you don't see the button in the Launch Bar, you might need to move it from the _Available Launchers_ section to the _Visible Launchers_ section:
    \ No newline at end of file diff --git a/docs/User Guide/User Guide/Advanced Usage/Advanced Showcases/Task Manager.md b/docs/User Guide/User Guide/Advanced Usage/Advanced Showcases/Task Manager.md index 20cf37c5e..13a4a5d94 100644 --- a/docs/User Guide/User Guide/Advanced Usage/Advanced Showcases/Task Manager.md +++ b/docs/User Guide/User Guide/Advanced Usage/Advanced Showcases/Task Manager.md @@ -15,7 +15,7 @@ New tasks are created in the TODO note which has `~child:template` [relation](.. ### Attributes -Task template defines several [promoted attributes](../Attributes/Promoted%20Attributes.md) - todoDate, doneDate, tags, location. Importantly it also defines `~runOnAttributeChange` relation - [event](../../Scripting/Events.md) handler which is run on attribute change. This [script](../../Scripting.md) handles when e.g. we fill out the doneDate attribute - meaning the task is done and should be moved to "Done" note and removed from TODO, locations and tags. +Task template defines several [promoted attributes](../Attributes/Promoted%20Attributes.md) - todoDate, doneDate, tags, location. Importantly it also defines `~runOnAttributeChange` relation - [event](../../Scripting/Backend%20scripts/Events.md) handler which is run on attribute change. This [script](../../Scripting.md) handles when e.g. we fill out the doneDate attribute - meaning the task is done and should be moved to "Done" note and removed from TODO, locations and tags. ### New task button diff --git a/docs/User Guide/User Guide/Advanced Usage/Attributes.md b/docs/User Guide/User Guide/Advanced Usage/Attributes.md index 1cfe040d8..89d397e33 100644 --- a/docs/User Guide/User Guide/Advanced Usage/Attributes.md +++ b/docs/User Guide/User Guide/Advanced Usage/Attributes.md @@ -3,14 +3,14 @@ In Trilium, attributes are key-value pairs assigned to notes, providing additional metadata or functionality. There are two primary types of attributes: -1. Labels can be used for a variety of purposes, such as storing metadata or configuring the behaviour of notes. Labels are also searchable, enhancing note retrieval. +1. Labels can be used for a variety of purposes, such as storing metadata or configuring the behavior of notes. Labels are also searchable, enhancing note retrieval. For more information, including predefined labels, see Labels. 2. Relations define connections between notes, similar to links. These can be used for metadata and scripting purposes. For more information, including a list of predefined relations, see Relations. -These attributes play a crucial role in organizing, categorising, and enhancing the functionality of notes. +These attributes play a crucial role in organizing, categorizing, and enhancing the functionality of notes. ## Viewing the list of attributes diff --git a/docs/User Guide/User Guide/Advanced Usage/Attributes/Labels.md b/docs/User Guide/User Guide/Advanced Usage/Attributes/Labels.md index 1a90f31cb..cb68dab93 100644 --- a/docs/User Guide/User Guide/Advanced Usage/Attributes/Labels.md +++ b/docs/User Guide/User Guide/Advanced Usage/Attributes/Labels.md @@ -39,4 +39,4 @@ This is a list of labels that Trilium natively supports. > [!TIP] > Some labels presented here end with a `*`. That means that there are multiple labels with the same prefix, consult the specific page linked in the description of that label for more information. -
    LabelDescription
    disableVersioningDisables automatic creation of Note Revisions for a particular note. Useful for e.g. large, but unimportant notes - e.g. large JS libraries used for scripting.
    versioningLimitLimits the maximum number of Note Revisions for a particular note, overriding the global settings.
    calendarRootMarks the note which should be used as root for Day Notes. Only one should be marked as such.
    archivedHides notes from default search results and dialogs. Archived notes can optionally be hidden in the Note Tree.
    excludeFromExportExcludes this note and its children when exporting.
    run, runOnInstance, runAtHourSee Events.
    disableInclusionScripts with this label won't be included into parent script execution.
    sorted

    Keeps child notes sorted by title alphabetically.

    When given a value, it will sort by the value of another label instead. If one of the child notes doesn't have the specified label, the title will be used for them instead.

    sortDirection

    If sorted is applied, specifies the direction of the sort:

    • ASC, ascending (default)
    • DESC, descending
    sortFoldersFirstIf sorted is applied, folders (notes with children) will be sorted as a group at the top, and the rest will be sorted.
    topIf sorted is applied to the parent note, keeps given note on top in its parent.
    hidePromotedAttributesHide Promoted Attributes on this note. Generally useful when defining inherited attributes, but the parent note doesn't need them.
    readOnlyMarks a note to be always be read-only, if it's a supported note (text, code, mermaid).
    autoReadOnlyDisabledDisables automatic read-only mode for the given note.
    appCssMarks CSS notes which are loaded into the Trilium application and can thus be used to modify Trilium's looks. See Custom app-wide CSS for more info.
    appThemeMarks CSS notes which are full Trilium themes and are thus available in Trilium options. See Theme development for more information.
    appThemeBaseSet to next, next-light, or next-dark to use the corresponding TriliumNext theme (auto, light or dark) as the base for a custom theme, instead of the legacy one. See Customize the Next theme for more information.
    cssClassValue of this label is then added as CSS class to the node representing given note in the Note Tree. This can be useful for advanced theming. Can be used in template notes.
    iconClassvalue of this label is added as a CSS class to the icon on the tree which can help visually distinguish the notes in the tree. Example might be bx bx-home - icons are taken from boxicons. Can be used in template notes.
    pageSizeSpecifies the number of items per page in Note List.
    customRequestHandlerSee Custom Request Handler.
    customResourceProviderSee Custom Resource Providers.
    widgetMarks this note as a custom widget which will be added to the Trilium component tree. See Custom Widgets for more information.
    searchHomeNew search notes will be created as children of this note (see Saved Search).
    workspace and related attributesSee Workspaces.
    inboxdefault inbox location for new notes - when you create a note using new note button in the sidebar, notes will be created as child notes in the note marked as with #inbox label.
    sqlConsoleHomeDefault location of SQL Console notes
    bookmarkedIndicates this note is a bookmark.
    bookmarkFolderNote with this label will appear in bookmarks as folder (allowing access to its children). See Bookmarks for more information.
    share*See the attribute reference in Sharing.
    displayRelations, hideRelationsComma delimited names of relations which should be displayed/hidden in a Relation Map (both the note type and the Note Map (Link map, Tree map) general functionality).
    titleTemplate

    Default title of notes created as children of this note. This value is evaluated as a JavaScript string and thus can be enriched with dynamic content via the injected now and parentNote variables.

    Examples:

    • \({parentNote.getLabel('authorName')}'s literary works
    • Log for \){now.format('YYYY-MM-DD HH:mm:ss')}
    • to mirror the parent's template.

    See Default Note Title for more info.

    templateThis note will appear in the selection of available template when creating new note. See Templates for more information.
    tocControls the display of the Table of contents for a given note. #toc or #toc=show to always display the table of contents, #toc=false to always hide it.
    colordefines color of the note in note tree, links etc. Use any valid CSS color value like 'red' or #a13d5f
    Note: this color may be automatically adjusted when displayed to ensure sufficient contrast with the background.
    keyboardShortcutDefines a keyboard shortcut which will immediately jump to this note. Example: 'ctrl+alt+e'. Requires frontend reload for the change to take effect.
    keepCurrentHoistingOpening this link won't change hoisting even if the note is not displayable in the current hoisted subtree.
    executeButtonTitle of the button which will execute the current code note
    executeDescriptionLonger description of the current code note displayed together with the execute button
    excludeFromNoteMapNotes with this label will be hidden from the Note Map.
    newNotesOnTopNew notes will be created at the top of the parent note, not on the bottom.
    hideHighlightWidgetHides the Highlights list widget
    hideChildrenOverviewHides the Note List for that particular note.
    printLandscapeWhen exporting to PDF, changes the orientation of the page to landscape instead of portrait.
    printPageSizeWhen exporting to PDF, changes the size of the page. Supported values: A0, A1, A2, A3, A4, A5, A6, Legal, Letter, Tabloid, Ledger.
    geolocationIndicates the latitude and longitude of a note, to be displayed in a Geo Map.
    calendar:*Defines specific options for the Calendar View.
    viewTypeSets the view of child notes (e.g. grid or list). See Note List for more information.
    \ No newline at end of file +
    LabelDescription
    disableVersioningDisables automatic creation of Note Revisions for a particular note. Useful for e.g. large, but unimportant notes - e.g. large JS libraries used for scripting.
    versioningLimitLimits the maximum number of Note Revisions for a particular note, overriding the global settings.
    calendarRootMarks the note which should be used as root for Day Notes. Only one should be marked as such.
    archivedHides notes from default search results and dialogs. Archived notes can optionally be hidden in the Note Tree.
    excludeFromExportExcludes this note and its children when exporting.
    run, runOnInstance, runAtHourSee Events.
    disableInclusionScripts with this label won't be included into parent script execution.
    sorted

    Keeps child notes sorted by title alphabetically.

    When given a value, it will sort by the value of another label instead. If one of the child notes doesn't have the specified label, the title will be used for them instead.

    sortDirection

    If sorted is applied, specifies the direction of the sort:

    • ASC, ascending (default)
    • DESC, descending
    sortFoldersFirstIf sorted is applied, folders (notes with children) will be sorted as a group at the top, and the rest will be sorted.
    topIf sorted is applied to the parent note, keeps given note on top in its parent.
    hidePromotedAttributesHide Promoted Attributes on this note. Generally useful when defining inherited attributes, but the parent note doesn't need them.
    readOnlyMarks a note to be always be read-only, if it's a supported note (text, code, mermaid).
    autoReadOnlyDisabledDisables automatic read-only mode for the given note.
    appCssMarks CSS notes which are loaded into the Trilium application and can thus be used to modify Trilium's looks. See Custom app-wide CSS for more info.
    appThemeMarks CSS notes which are full Trilium themes and are thus available in Trilium options. See Theme development for more information.
    appThemeBaseSet to next, next-light, or next-dark to use the corresponding TriliumNext theme (auto, light or dark) as the base for a custom theme, instead of the legacy one. See Customize the Next theme for more information.
    cssClassValue of this label is then added as CSS class to the node representing given note in the Note Tree. This can be useful for advanced theming. Can be used in template notes.
    iconClassvalue of this label is added as a CSS class to the icon on the tree which can help visually distinguish the notes in the tree. Example might be bx bx-home - icons are taken from boxicons. Can be used in template notes.
    pageSizeSpecifies the number of items per page in Note List.
    customRequestHandlerSee Custom Request Handler.
    customResourceProviderSee Custom Resource Providers.
    widgetMarks this note as a custom widget which will be added to the Trilium component tree. See Custom Widgets for more information.
    searchHomeNew search notes will be created as children of this note (see Saved Search).
    workspace and related attributesSee Workspaces.
    inboxdefault inbox location for new notes - when you create a note using new note button in the sidebar, notes will be created as child notes in the note marked as with #inbox label.
    sqlConsoleHomeDefault location of SQL Console notes
    bookmarkedIndicates this note is a bookmark.
    bookmarkFolderNote with this label will appear in bookmarks as folder (allowing access to its children). See Bookmarks for more information.
    share*See the attribute reference in Sharing.
    displayRelations, hideRelationsComma delimited names of relations which should be displayed/hidden in a Relation Map (both the note type and the Note Map (Link map, Tree map) general functionality).
    titleTemplate

    Default title of notes created as children of this note. This value is evaluated as a JavaScript string and thus can be enriched with dynamic content via the injected now and parentNote variables.

    Examples:

    • \({parentNote.getLabel('authorName')}'s literary works
    • Log for \){now.format('YYYY-MM-DD HH:mm:ss')}
    • to mirror the parent's template.

    See Default Note Title for more info.

    templateThis note will appear in the selection of available template when creating new note. See Templates for more information.
    tocControls the display of the Table of contents for a given note. #toc or #toc=show to always display the table of contents, #toc=false to always hide it.
    colordefines color of the note in note tree, links etc. Use any valid CSS color value like 'red' or #a13d5f
    Note: this color may be automatically adjusted when displayed to ensure sufficient contrast with the background.
    keyboardShortcutDefines a keyboard shortcut which will immediately jump to this note. Example: 'ctrl+alt+e'. Requires frontend reload for the change to take effect.
    keepCurrentHoistingOpening this link won't change hoisting even if the note is not displayable in the current hoisted subtree.
    executeButtonTitle of the button which will execute the current code note
    executeDescriptionLonger description of the current code note displayed together with the execute button
    excludeFromNoteMapNotes with this label will be hidden from the Note Map.
    newNotesOnTopNew notes will be created at the top of the parent note, not on the bottom.
    hideHighlightWidgetHides the Highlights list widget
    hideChildrenOverviewHides the Note List for that particular note.
    printLandscapeWhen exporting to PDF, changes the orientation of the page to landscape instead of portrait.
    printPageSizeWhen exporting to PDF, changes the size of the page. Supported values: A0, A1, A2, A3, A4, A5, A6, Legal, Letter, Tabloid, Ledger.
    geolocationIndicates the latitude and longitude of a note, to be displayed in a Geo Map.
    calendar:*Defines specific options for the Calendar View.
    viewTypeSets the view of child notes (e.g. grid or list). See Note List for more information.
    \ No newline at end of file diff --git a/docs/User Guide/User Guide/Advanced Usage/Attributes/Relations.md b/docs/User Guide/User Guide/Advanced Usage/Attributes/Relations.md index 454e7d007..6e1e9aa1f 100644 --- a/docs/User Guide/User Guide/Advanced Usage/Attributes/Relations.md +++ b/docs/User Guide/User Guide/Advanced Usage/Attributes/Relations.md @@ -43,7 +43,7 @@ These relations are supported and used internally by Trilium. | Label | Description | | --- | --- | -| `runOn*` | See Events | +| `runOn*` | See Events | | `template` | note's attributes will be inherited even without a parent-child relationship, note's content and subtree will be added to instance notes if empty. See documentation for details. | | `inherit` | note's attributes will be inherited even without a parent-child relationship. See Templates for a similar concept. See Attribute Inheritance in the documentation. | | `renderNote` | notes of type Render Note will be rendered using a code note (HTML or script) and it is necessary to point using this relation to which note should be rendered | diff --git a/docs/User Guide/User Guide/Advanced Usage/Custom Request Handler.md b/docs/User Guide/User Guide/Advanced Usage/Custom Request Handler.md index 52991f136..6d2c1e734 100644 --- a/docs/User Guide/User Guide/Advanced Usage/Custom Request Handler.md +++ b/docs/User Guide/User Guide/Advanced Usage/Custom Request Handler.md @@ -14,7 +14,7 @@ const {secret, title, content} = req.body; if (req.method == 'POST' && secret === 'secret-password') { // notes must be saved somewhere in the tree hierarchy specified by a parent note. // This is defined by a relation from this code note to the "target" parent note - // alternetively you can just use constant noteId for simplicity (get that from "Note Info" dialog of the desired parent note) + // alternatively you can just use constant noteId for simplicity (get that from "Note Info" dialog of the desired parent note) const targetParentNoteId = api.currentNote.getRelationValue('targetNote'); const {note} = api.createTextNote(targetParentNoteId, title, content); @@ -37,7 +37,7 @@ This script note has also following two attributes: Let's test this by using an HTTP client to send a request: ``` -POST http://my.trilium.org/custom/create-note +POST http://your-trilium-server/custom/create-note Content-Type: application/json { @@ -70,7 +70,7 @@ For more information, see [Custom Resource Providers](Custom%20Resource%20Provi REST request paths often contain parameters in the URL, e.g.: ``` -http://my.trilium.org/custom/notes/123 +http://your-trilium-server/custom/notes/123 ``` The last part is dynamic so the matching of the URL must also be dynamic - for this reason the matching is done with regular expressions. Following `customRequestHandler` value would match it: @@ -85,4 +85,4 @@ Additionally, this also defines a matching group with the use of parenthesis whi const noteId = api.pathParams[0]; ``` -Often you also need query params (as in e.g. `http://my.trilium.org/custom/notes?noteId=123`), you can get those with standard express `req.query.noteId`. \ No newline at end of file +Often you also need query params (as in e.g. `http://your-trilium-server/custom/notes?noteId=123`), you can get those with standard express `req.query.noteId`. \ No newline at end of file diff --git a/docs/User Guide/User Guide/Advanced Usage/Nightly release.md b/docs/User Guide/User Guide/Advanced Usage/Nightly release.md new file mode 100644 index 000000000..c9c2aac09 --- /dev/null +++ b/docs/User Guide/User Guide/Advanced Usage/Nightly release.md @@ -0,0 +1,34 @@ +# Nightly release +Nightly releases are versions built every day, containing the latest improvements and bugfixes, directly from the main development branch. These versions are generally useful in preparation for a release, to ensure that there are no significant bugs that need to be addressed first, or they can be used to confirm whether a particular bug is fixed or feature is well implemented. + +## Regarding the stability + +Despite being on a development branch, generally the main branch is pretty stable since PRs are tested before they are merged. If you notice any issues, feel free to report them either via a ticket or via the Matrix. + +## Downloading the nightly release manually + +Go to [github.com/TriliumNext/Trilium/releases/tag/nightly](https://github.com/TriliumNext/Trilium/releases/tag/nightly) and look for the artifacts starting with `TriliumNotes-main`. Choose the appropriate one for your platform (e.g. `windows-x64.zip`). + +Depending on your use case, you can either test the portable version or even use the installer. + +> [!NOTE] +> If you choose the installable version (e.g. the .exe on Windows), it will replace your stable installation. + +> [!IMPORTANT] +> By default, the nightly uses the same database as the production version. Generally you could easily downgrade if needed. However, if there are changes to the database or sync version, it will not be possible to downgrade without having to restore from a backup. + +## Automatically download and install the latest nightly + +This is pretty useful if you are a beta tester that wants to periodically update their version: + +On Ubuntu: + +``` +#!/usr/bin/env bash + +name=TriliumNotes-linux-x64-nightly.deb +rm -f $name* +wget https://github.com/TriliumNext/Trilium/releases/download/nightly/$name +sudo apt-get install ./$name +rm $name +``` \ No newline at end of file diff --git a/docs/User Guide/User Guide/Advanced Usage/Read-only database.md b/docs/User Guide/User Guide/Advanced Usage/Read-only database.md new file mode 100644 index 000000000..cacdc9675 --- /dev/null +++ b/docs/User Guide/User Guide/Advanced Usage/Read-only database.md @@ -0,0 +1,32 @@ +# Read-only database +> [!WARNING] +> This functionality is still in preview, expect possible issues or even the feature disappearing completely. +> Feel free to [report](../Troubleshooting/Reporting%20issues.md) any issues you might have. + +The read-only database is an alternative to Sharing notes. Although the share functionality works pretty well to publish pages to the Internet in a wiki, blog-like format it does not offer the full functionality behind Trilium (such as the advanced Search or the interactivity behind Collections or the various Note Types). + +When the database is in read-only mode, the Trilium application can be used as normal, but editing is disabled and changes are made in-memory only. + +## What it does + +* All notes are read-only, without the possibility of editing them. +* Features that would normally alter the database such as the list of recent notes are disabled. + +## Limitations + +* Some features might “slip through” and still end up creating a note, for example. + * However, the database is still read-only, so all modifications will be reset if the server is restarted. + * Whenever this occurs, `ERROR: read-only DB ignored` will be shown in the logs. + +## Setting a database as read-only + +First, make sure the database is initialized (e.g. the first set up is complete). Then modify the [config.ini](Configuration%20\(config.ini%20or%20e.md) by looking for the `[General]` section and adding a new `readOnly` field: + +``` +[General] +readOnly=true +``` + +If your server is already running, restart it to apply the changes. + +Similarly, to disable read-only remove the line or set it to `false`. \ No newline at end of file diff --git a/docs/User Guide/User Guide/Basic Concepts and Features/Navigation/Search.md b/docs/User Guide/User Guide/Basic Concepts and Features/Navigation/Search.md index 70dd3632a..36aebff51 100644 --- a/docs/User Guide/User Guide/Basic Concepts and Features/Navigation/Search.md +++ b/docs/User Guide/User Guide/Basic Concepts and Features/Navigation/Search.md @@ -13,7 +13,7 @@ Note search enables you to find notes by searching for text in the title, conten To search for notes, click on the magnifying glass icon on the toolbar or press the keyboard [shortcut](../Keyboard%20Shortcuts.md). 1. Set the text to search for in the _Search string_ field. - 1. Apart from searching for words ad-literam, there is also the possibility to search for attributes or properties of notes. + 1. Apart from searching for words literally, there is also the possibility to search for attributes or properties of notes. 2. See the examples below for more information. 2. To limit the search to a note and its sub-children, set a note in _Ancestor_. 1. This value is also pre-filled if the search is triggered from a [hoisted note](Note%20Hoisting.md) or a [workspace](Workspaces.md). diff --git a/docs/User Guide/User Guide/Basic Concepts and Features/Notes.md b/docs/User Guide/User Guide/Basic Concepts and Features/Notes.md index 8cb069e53..d461a3506 100644 --- a/docs/User Guide/User Guide/Basic Concepts and Features/Notes.md +++ b/docs/User Guide/User Guide/Basic Concepts and Features/Notes.md @@ -25,7 +25,7 @@ When you delete a note in Trilium, it is actually only marked for deletion (soft Within (by default) 7 days, it is possible to undelete these soft-deleted notes - open the Recent Changes dialog, and you will see a list of all modified notes including the deleted ones. Notes available for undeletion have a link to do so. This is kind of "trash can" functionality known from e.g. Windows. -Clicking an undelete will recover the note, it's content and attributes - note should be just as before being deleted. This action will also undelete note's children which have been deleted in the same action. +Clicking an undelete will recover the note, its content and attributes - note should be just as before being deleted. This action will also undelete note's children which have been deleted in the same action. To be able to undelete a note, it is necessary that deleted note's parent must be undeleted (otherwise there's no place where we can undelete it to). This might become a problem when you delete more notes in succession - the solution is then undelete in the reverse order of your deletion. diff --git a/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Launch Bar.md b/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Launch Bar.md index 795e02602..d0ba7aecf 100644 --- a/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Launch Bar.md +++ b/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Launch Bar.md @@ -56,7 +56,7 @@ Right click either the _Available launchers_ or _Visible launchers_ sections and 2. Optionally, set a `keyboardShortcut` to trigger the launcher. 3. **Custom Widget** - Allows defining a custom widget to be rendered inside the launcher. See [Widget Basics](../../Scripting/Custom%20Widgets/Widget%20Basics.md) for more information. + Allows defining a custom widget to be rendered inside the launcher. See [Widget Basics](../../Scripting/Frontend%20Basics/Custom%20Widgets/Widget%20Basics.md) for more information. 4. **Spacers** Launchers that create some distance between other launchers for better visual distinction. diff --git a/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.md b/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.md index 8fd7e37d2..5cbfc0ff3 100644 --- a/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.md +++ b/docs/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.md @@ -20,7 +20,7 @@ If you are using the _Fixed_ formatting toolbar, all the formatting buttons for * As a more advanced use, it's possible to change the note type in order to modify the [source code](../../Advanced%20Usage/Note%20source.md) of a note. * _**Protect the note**_ toggles whether the current note is encrypted and accessible only by entering the protected session. See [Protected Notes](../Notes/Protected%20Notes.md) for more information. * _**Editable**_ changes whether the current note: - * Enters [read-only mode](../Notes/Read-Only%20Notes.md) automatically if the note is too big (default behaviour). + * Enters [read-only mode](../Notes/Read-Only%20Notes.md) automatically if the note is too big (default behavior). * Is always in read-only mode (however it can still be edited temporarily). * Is always editable, regardless of its size. * _**Bookmark**_ toggles the display of the current note into the [Launch Bar](Launch%20Bar.md) for easy access. See [Bookmarks](../Navigation/Bookmarks.md) for more information. diff --git a/docs/User Guide/User Guide/Collections.md b/docs/User Guide/User Guide/Collections.md index b97b4d952..3a9fc9728 100644 --- a/docs/User Guide/User Guide/Collections.md +++ b/docs/User Guide/User Guide/Collections.md @@ -1,5 +1,5 @@ # Collections -Collections are a unique type of notes that don't have a content, but instead display its child notes in various presentation methods. +Collections are a unique type of note that don't have content, but instead display their child notes in various presentation methods. ## Main collections @@ -28,7 +28,7 @@ To change the configuration of a collection or even switch to a different collec ## Archived notes -By default, [archived notes](Basic%20Concepts%20and%20Features/Notes/Archived%20Notes.md) will not be shown in collections. This behaviour can be changed by going to _Collection Properties_ in the Ribbon and checking _Show archived notes_. +By default, [archived notes](Basic%20Concepts%20and%20Features/Notes/Archived%20Notes.md) will not be shown in collections. This behavior can be changed by going to _Collection Properties_ in the Ribbon and checking _Show archived notes_. Archived notes will be generally indicated by being greyed out as opposed to the normal ones. diff --git a/docs/User Guide/User Guide/Installation & Setup/Data directory.md b/docs/User Guide/User Guide/Installation & Setup/Data directory.md index c2f3650c5..3d66bafe9 100644 --- a/docs/User Guide/User Guide/Installation & Setup/Data directory.md +++ b/docs/User Guide/User Guide/Installation & Setup/Data directory.md @@ -26,7 +26,17 @@ If you want to back up your Trilium data, just backup this single directory - it ### Changing the location of data directory -If you want to use some other location for the data directory than the default one, you may change it via TRILIUM\_DATA\_DIR environment variable to some other location: +If you want to use some other location for the data directory than the default one, you may change it via `TRILIUM_DATA_DIR` environment variable to some other location: + +### Windows + +1. Press the Windows key on your keyboard. +2. Search and select “Edit the system variables”. +3. Press the “Environment Variables…” button in the bottom-right of the newly opened screen. +4. On the top section ("User variables for \[user\]"), press the “New…” button. +5. In the _Variable name_ field insert `TRILIUM_DATA_DIR`. +6. Press the _Browse Directory…_ button and select the new directory where to store the database. +7. Close all the windows by pressing the _OK_ button for each of them. #### Linux @@ -43,11 +53,6 @@ To load it manually, you need to use `launchctl setenv TRILIUM_DATA_DIR Synchronization guide for detailed instructions. \ No newline at end of file +For Trilium desktop users who wish to synchronize their data with a server instance, refer to the Synchronization guide for detailed instructions. \ No newline at end of file diff --git a/docs/User Guide/User Guide/Installation & Setup/Server Installation.md b/docs/User Guide/User Guide/Installation & Setup/Server Installation.md index eb0054c91..ceae67f84 100644 --- a/docs/User Guide/User Guide/Installation & Setup/Server Installation.md +++ b/docs/User Guide/User Guide/Installation & Setup/Server Installation.md @@ -32,7 +32,7 @@ export TRILIUM_DATA_DIR=/home/myuser/data/my-trilium-data ### Disabling / Modifying the Upload Limit -If you're running into the 250MB limit imposed on the server by default, and you'd like to increase the upload limit, you can set the `TRILIUM_NO_UPLOAD_LIMIT` environment variable to `true` disable it completely: +If you're running into the 250MB limit imposed on the server by default, and you'd like to increase the upload limit, you can set the `TRILIUM_NO_UPLOAD_LIMIT` environment variable to `true` to disable it completely: ``` export TRILIUM_NO_UPLOAD_LIMIT=true diff --git a/docs/User Guide/User Guide/Note Types.md b/docs/User Guide/User Guide/Note Types.md index 2e0540dcf..27958b4ab 100644 --- a/docs/User Guide/User Guide/Note Types.md +++ b/docs/User Guide/User Guide/Note Types.md @@ -1,5 +1,5 @@ # Note Types -One core features of Trilium is that it supports multiple types of notes, depending on the need. +One of the core features of Trilium is that it supports multiple types of notes, depending on the need. ## Creating a new note with a different type via the note tree diff --git a/docs/User Guide/User Guide/Scripting.md b/docs/User Guide/User Guide/Scripting.md index f5724f8a3..b7fad64dc 100644 --- a/docs/User Guide/User Guide/Scripting.md +++ b/docs/User Guide/User Guide/Scripting.md @@ -1,18 +1,18 @@ # Scripting Trilium supports creating Code notes, i.e. notes which allow you to store some programming code and highlight it. Special case is JavaScript code notes which can also be executed inside Trilium which can in conjunction with Script API provide extra functionality. -## Scripting +## Architecture Overview To go further I must explain basic architecture of Trilium - in its essence it is a classic web application - it has these two main components: * frontend running in the browser (using HTML, CSS, JavaScript) - this is mainly used to interact with the user, display notes etc. * backend running JavaScript code in node.js runtime - this is responsible for e.g. storing notes, encrypting them etc. -So we have frontend and backend, each with their own set of responsibilities, but their common feature is that they both run JavaScript code. Add to this the fact, that we're able to create JavaScript \[\[code notes\]\] and we're onto something. +So we have frontend and backend, each with their own set of responsibilities, but their common feature is that they both run JavaScript code. Add to this the fact, that we're able to create JavaScript code notes and we're onto something. ## Use cases -* "New Task" launcher button +* "New Task" launcher button ## Action handler @@ -34,7 +34,7 @@ You can see more scripting with explanation in Events. +See Events. ## Script API diff --git a/docs/User Guide/User Guide/Scripting/Events.md b/docs/User Guide/User Guide/Scripting/Backend scripts/Events.md similarity index 78% rename from docs/User Guide/User Guide/Scripting/Events.md rename to docs/User Guide/User Guide/Scripting/Backend scripts/Events.md index 6dbeeeba6..227acd5f1 100644 --- a/docs/User Guide/User Guide/Scripting/Events.md +++ b/docs/User Guide/User Guide/Scripting/Backend scripts/Events.md @@ -1,15 +1,15 @@ # Events -[Script](../Scripting.md) notes can be triggered by events. Note that these are backend events and thus relation need to point to the "JS backend" code note. +[Script](../../Scripting.md) notes can be triggered by events. Note that these are backend events and thus relation need to point to the "JS backend" code note. ## Global events Global events are attached to the script note via label. Simply create e.g. "run" label with some of these values and script note will be executed once the event occurs. -
    LabelDescription
    run

    Defines on which events script should run. Possible values are:

    • frontendStartup - when Trilium frontend starts up (or is refreshed), but not on mobile.
    • mobileStartup - when Trilium frontend starts up (or is refreshed), on mobile.
    • backendStartup - when Trilium backend starts up
    • hourly - run once an hour. You can use additional label runAtHour to specify at which hour, on the back-end.
    • daily - run once a day, on the back-end
    runOnInstanceSpecifies that the script should only run on a particular Trilium instance.
    runAtHourOn which hour should this run. Should be used together with #run=hourly. Can be defined multiple times for more runs during the day.
    +
    LabelDescription
    run

    Defines on which events script should run. Possible values are:

    • frontendStartup - when Trilium frontend starts up (or is refreshed), but not on mobile.
    • mobileStartup - when Trilium frontend starts up (or is refreshed), on mobile.
    • backendStartup - when Trilium backend starts up
    • hourly - run once an hour. You can use additional label runAtHour to specify at which hour, on the back-end.
    • daily - run once a day, on the back-end
    runOnInstanceSpecifies that the script should only run on a particular Trilium instance.
    runAtHourOn which hour should this run. Should be used together with #run=hourly. Can be defined multiple times for more runs during the day.
    ## Entity events -Other events are bound to some entity, these are defined as [relations](../Advanced%20Usage/Attributes.md) - meaning that script is triggered only if note has this script attached to it through relations (or it can inherit it). +Other events are bound to some entity, these are defined as [relations](../../Advanced%20Usage/Attributes.md) - meaning that script is triggered only if note has this script attached to it through relations (or it can inherit it). | Relation | Description | | --- | --- | diff --git a/docs/User Guide/User Guide/Scripting/Backend scripts/Server-side imports.md b/docs/User Guide/User Guide/Scripting/Backend scripts/Server-side imports.md new file mode 100644 index 000000000..ddc795aa0 --- /dev/null +++ b/docs/User Guide/User Guide/Scripting/Backend scripts/Server-side imports.md @@ -0,0 +1,11 @@ +# Server-side imports +Older versions of Trilium Notes allowed the use of Common.js module imports inside backend scripts, such as: + +``` +const isBetween = require('dayjs/plugin/isBetween') +api.dayjs.extend(isBetween) +``` + +For newer versions, Node.js imports are **not officially supported anymore**, since we've added a bundler which makes it more difficult to reuse dependencies. + +Theoretically it's still possible to use imports by manually setting up a `node_modules` in the server directory via `npm` or `pnpm`. \ No newline at end of file diff --git a/docs/User Guide/User Guide/Scripting/Examples/New Task launcher button.md b/docs/User Guide/User Guide/Scripting/Examples/New Task launcher button.md deleted file mode 100644 index 85e834b8b..000000000 --- a/docs/User Guide/User Guide/Scripting/Examples/New Task launcher button.md +++ /dev/null @@ -1,47 +0,0 @@ -# "New Task" launcher button -In this example we are going to extend the functionality of Task Manager showcase (which comes by default with Trilium) by adding a button in the Launch Bar  (![](New%20Task%20launcher%20button_i.png)) to create a new task automatically and open it. - -## Creating the note - -1. First, create a new Code note type with the _JS frontend_ language. -2. Define the `#run=frontendStartup` label in Attributes. - -## Content of the script - -Copy-paste the following script: - -```javascript -api.addButtonToToolbar({ - title: "New task", - icon: "task", - shortcut: "alt+n", - action: async () => { - const taskNoteId = await api.runOnBackend(() => { - const todoRootNote = api.getNoteWithLabel("taskTodoRoot"); - const resp = api.createTextNote(todoRootNote.noteId, "New task", "") - return resp.note.noteId; - }); - - await api.waitUntilSynced(); - await api.activateNewNote(taskNoteId); - } -}); -``` - -## Testing the functionality - -Since we set the script to be run on start-up, all we need to do is to [refresh the application](../../Troubleshooting/Refreshing%20the%20application.md). - -## Understanding how the script works - -
    api.addButtonToToolbar({
    -	title: "New task",
    -    icon: "task",
    -    shortcut: "alt+n",
    -    action: async () => {
    -    	// [...]
    -    }
    -});

    This uses the Front-end API to create a icon in the Launch Bar, by specifying:

    • A title
    • A corresponding boxicons icon (without the bx- prefix).
    • Optionally, a keyboard shortcut to assign to it.
    • The action, which will be executed when the button is pressed.
    const taskNoteId = await api.runOnBackend(() => {
    -    // Shown below.           
    -    return resp.note.noteId;
    -});
    • This portion of code is actually executed on the server (backend) and not on the client (i.e. browser).
      • The reason is that the creating notes is the responsibility of the server.
    • Here we can also see that it is possible to return results from the server execution and read them in the client (taskNoteId).
    const todoRootNote = api.getNoteWithLabel("taskTodoRoot");
    • Here we identify a note with the label #taskTodoRoot. This is how the Task Manager showcase knows where to place all the different tasks.
    • Normally this might return a null value if no such note could be identified, but error handling is outside the scope of this example. 
    const resp = api.createTextNote(todoRootNote.noteId, "New task", "")
    • We create a new child note within the to-do root note (first argument) with the title “New task" (second argument) and no content by default (third argument).
    await api.waitUntilSynced();
    • Back on the client, since we created a new note on the server, we now need to wait for the change to be reflected in the client.
    await api.activateNewNote(taskNoteId);
    • Since we know the ID of the newly created note, all we have to do now is to show this note to the user.
    \ No newline at end of file diff --git a/docs/User Guide/User Guide/Scripting/Frontend Basics.md b/docs/User Guide/User Guide/Scripting/Frontend Basics.md index 2557deed7..13c47823d 100644 --- a/docs/User Guide/User Guide/Scripting/Frontend Basics.md +++ b/docs/User Guide/User Guide/Scripting/Frontend Basics.md @@ -54,4 +54,4 @@ Conversely to scripts, widgets do have some specific requirements in order to wo ### Tutorial -For more information on building widgets, take a look at [Widget Basics](Custom%20Widgets/Widget%20Basics.md). \ No newline at end of file +For more information on building widgets, take a look at [Widget Basics](Frontend%20Basics/Custom%20Widgets/Widget%20Basics.md). \ No newline at end of file diff --git a/docs/User Guide/User Guide/Scripting/Custom Widgets.md b/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets.md similarity index 100% rename from docs/User Guide/User Guide/Scripting/Custom Widgets.md rename to docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets.md diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Scripting/Widgets/CSS.md b/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/CSS.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Old documentation/Scripting/Widgets/CSS.md rename to docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/CSS.md diff --git a/docs/Developer Guide/Developer Guide/Old documentation/Scripting/Widgets/Right pane widget.md b/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.md similarity index 100% rename from docs/Developer Guide/Developer Guide/Old documentation/Scripting/Widgets/Right pane widget.md rename to docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.md diff --git a/docs/User Guide/User Guide/Scripting/Custom Widgets/Widget Basics.md b/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics.md similarity index 75% rename from docs/User Guide/User Guide/Scripting/Custom Widgets/Widget Basics.md rename to docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics.md index b6e2a95ca..474cba983 100644 --- a/docs/User Guide/User Guide/Scripting/Custom Widgets/Widget Basics.md +++ b/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics.md @@ -22,10 +22,10 @@ module.exports = new MyWidget(); To implement this widget: 1. Create a new `JS Frontend` note in Trilium and paste in the code above. -2. Assign the `#widget` [attribute](../../Advanced%20Usage/Attributes.md) to the [note](../../Basic%20Concepts%20and%20Features/Notes.md). +2. Assign the `#widget` [attribute](../../../Advanced%20Usage/Attributes.md) to the [note](../../../Basic%20Concepts%20and%20Features/Notes.md). 3. Restart Trilium or reload the window. -To verify that the widget is working, open the developer tools (`Cmd` + `Shift` + `I`) and run `document.querySelector("#my-widget")`. If the element is found, the widget is functioning correctly. If `undefined` is returned, double-check that the [note](../../Basic%20Concepts%20and%20Features/Notes.md) has the `#widget` [attribute](../../Advanced%20Usage/Attributes.md). +To verify that the widget is working, open the developer tools (`Cmd` + `Shift` + `I`) and run `document.querySelector("#my-widget")`. If the element is found, the widget is functioning correctly. If `undefined` is returned, double-check that the [note](../../../Basic%20Concepts%20and%20Features/Notes.md) has the `#widget` [attribute](../../../Advanced%20Usage/Attributes.md). ### Step 2: Adding an UI Element @@ -85,7 +85,7 @@ After reloading Trilium, the button should now appear at the bottom left of the ### Step 4: Adding User Interaction -Let’s make the button interactive by showing a message when it’s clicked. We'll use the `api.showMessage` method from the [Script API](../Script%20API.md). +Let’s make the button interactive by showing a message when it’s clicked. We'll use the `api.showMessage` method from the [Script API](../../Script%20API.md). ``` class MyWidget extends api.BasicWidget { @@ -108,4 +108,11 @@ class MyWidget extends api.BasicWidget { module.exports = new MyWidget(); ``` -Reload the application one last time. When you click the button, a "Hello World!" message should appear, confirming that your widget is fully functional. \ No newline at end of file +`parentWidget()` can be given the following values: + +* `left-pane` - This renders the widget on the left side of the screen where the note tree lives. +* `center-pane` - This renders the widget in the center of the layout in the same location that notes and splits appear. +* `note-detail-pane` - This renders the widget _with_ the note in the center pane. This means it can appear multiple times with splits. +* `right-pane` - This renders the widget to the right of any opened notes. + +[Reload](../../../Troubleshooting/Refreshing%20the%20application.md) the application one last time. When you click the button, a "Hello World!" message should appear, confirming that your widget is fully functional. \ No newline at end of file diff --git a/docs/User Guide/User Guide/Scripting/Custom Widgets/Word count widget.md b/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget.md similarity index 88% rename from docs/User Guide/User Guide/Scripting/Custom Widgets/Word count widget.md rename to docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget.md index ad8c1c351..8b6be5684 100644 --- a/docs/User Guide/User Guide/Scripting/Custom Widgets/Word count widget.md +++ b/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget.md @@ -1,8 +1,8 @@ # Word count widget > [!TIP] -> This widget is also present in new installations in the Demo Notes. +> This widget is also present in new installations in the Demo Notes. -Create a Code note of type JS frontend and **give it a** `#widget` **label**. +Create a Code note of type JS frontend and **give it a** `#widget` **label**. ``` /* @@ -82,7 +82,7 @@ class WordCountWidget extends api.NoteContextAwareWidget { module.exports = new WordCountWidget(); ``` -After you make changes it is necessary to [restart Trilium](../../Troubleshooting/Refreshing%20the%20application.md) so that the layout can be rebuilt. +After you make changes it is necessary to [restart Trilium](../../../Troubleshooting/Refreshing%20the%20application.md) so that the layout can be rebuilt. At the bottom of the note you can see the resulting widget: diff --git a/docs/User Guide/User Guide/Scripting/Custom Widgets/Word count widget_image.png b/docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget_image.png similarity index 100% rename from docs/User Guide/User Guide/Scripting/Custom Widgets/Word count widget_image.png rename to docs/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget_image.png diff --git a/docs/User Guide/User Guide/Scripting/Examples/Downloading responses from Goo.md b/docs/User Guide/User Guide/Scripting/Frontend Basics/Examples/Downloading responses from Goo.md similarity index 100% rename from docs/User Guide/User Guide/Scripting/Examples/Downloading responses from Goo.md rename to docs/User Guide/User Guide/Scripting/Frontend Basics/Examples/Downloading responses from Goo.md diff --git a/docs/User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button.md b/docs/User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button.md new file mode 100644 index 000000000..6740c047f --- /dev/null +++ b/docs/User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button.md @@ -0,0 +1,47 @@ +# "New Task" launcher button +In this example we are going to extend the functionality of Task Manager showcase (which comes by default with Trilium) by adding a button in the Launch Bar  (![](New%20Task%20launcher%20button_i.png)) to create a new task automatically and open it. + +## Creating the note + +1. First, create a new Code note type with the _JS frontend_ language. +2. Define the `#run=frontendStartup` label in Attributes. + +## Content of the script + +Copy-paste the following script: + +```javascript +api.addButtonToToolbar({ + title: "New task", + icon: "task", + shortcut: "alt+n", + action: async () => { + const taskNoteId = await api.runOnBackend(() => { + const todoRootNote = api.getNoteWithLabel("taskTodoRoot"); + const resp = api.createTextNote(todoRootNote.noteId, "New task", "") + return resp.note.noteId; + }); + + await api.waitUntilSynced(); + await api.activateNewNote(taskNoteId); + } +}); +``` + +## Testing the functionality + +Since we set the script to be run on start-up, all we need to do is to [refresh the application](../../../Troubleshooting/Refreshing%20the%20application.md). + +## Understanding how the script works + +
    api.addButtonToToolbar({
    +	title: "New task",
    +    icon: "task",
    +    shortcut: "alt+n",
    +    action: async () => {
    +    	// [...]
    +    }
    +});

    This uses the Front-end API to create a icon in the Launch Bar, by specifying:

    • A title
    • A corresponding boxicons icon (without the bx- prefix).
    • Optionally, a keyboard shortcut to assign to it.
    • The action, which will be executed when the button is pressed.
    const taskNoteId = await api.runOnBackend(() => {
    +    // Shown below.           
    +    return resp.note.noteId;
    +});
    • This portion of code is actually executed on the server (backend) and not on the client (i.e. browser).
      • The reason is that the creating notes is the responsibility of the server.
    • Here we can also see that it is possible to return results from the server execution and read them in the client (taskNoteId).
    const todoRootNote = api.getNoteWithLabel("taskTodoRoot");
    • Here we identify a note with the label #taskTodoRoot. This is how the Task Manager showcase knows where to place all the different tasks.
    • Normally this might return a null value if no such note could be identified, but error handling is outside the scope of this example. 
    const resp = api.createTextNote(todoRootNote.noteId, "New task", "")
    • We create a new child note within the to-do root note (first argument) with the title “New task" (second argument) and no content by default (third argument).
    await api.waitUntilSynced();
    • Back on the client, since we created a new note on the server, we now need to wait for the change to be reflected in the client.
    await api.activateNewNote(taskNoteId);
    • Since we know the ID of the newly created note, all we have to do now is to show this note to the user.
    \ No newline at end of file diff --git a/docs/User Guide/User Guide/Scripting/Examples/New Task launcher button_i.png b/docs/User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button_i.png similarity index 100% rename from docs/User Guide/User Guide/Scripting/Examples/New Task launcher button_i.png rename to docs/User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button_i.png diff --git a/docs/User Guide/User Guide/Scripting/Examples/Using promoted attributes .png b/docs/User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes .png similarity index 100% rename from docs/User Guide/User Guide/Scripting/Examples/Using promoted attributes .png rename to docs/User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes .png diff --git a/docs/User Guide/User Guide/Scripting/Examples/Using promoted attributes to c.md b/docs/User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes to c.md similarity index 100% rename from docs/User Guide/User Guide/Scripting/Examples/Using promoted attributes to c.md rename to docs/User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes to c.md diff --git a/docs/User Guide/User Guide/Troubleshooting.md b/docs/User Guide/User Guide/Troubleshooting.md index f439d1185..3be0af47f 100644 --- a/docs/User Guide/User Guide/Troubleshooting.md +++ b/docs/User Guide/User Guide/Troubleshooting.md @@ -1,5 +1,5 @@ # Troubleshooting -As Trilium is currently in beta, encountering bugs is to be expected. +While Trilium is actively maintained and stable, encountering bugs is possible. ## General Quick Fix @@ -21,7 +21,7 @@ TRILIUM_START_NOTE_ID=root ./trilium ## Broken Script Prevents Application Startup -If a custom script causes Triliumto crash, and it is set as a startup script or in an active [custom widget](Scripting/Custom%20Widgets.md), start Triliumin "safe mode" to prevent any custom scripts from executing: +If a custom script causes Trilium to crash, and it is set as a startup script or in an active [custom widget](Scripting/Frontend%20Basics/Custom%20Widgets.md), start Triliumin "safe mode" to prevent any custom scripts from executing: ``` TRILIUM_SAFE_MODE=true ./trilium diff --git a/docs/index.md b/docs/index.md index 5bf104216..33bbff30d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -21,27 +21,27 @@ Trilium Notes is a powerful, feature-rich note-taking application designed for b
    -- :material-rocket-launch-outline: **[Quick Start Guide](User%20Guide/quick-start.md)** +- :material-rocket-launch-outline: **[Quick Start Guide](User%20Guide/User%20Guide/Quick%20Start.md)** Get up and running with Trilium in minutes -- :material-download: **[Installation](User%20Guide/installation.md)** +- :material-download: **[Desktop Installation](User%20Guide/User%20Guide/Installation%20%26%20Setup/Desktop%20Installation.md)** - Download and install Trilium on your platform + Download and install Trilium on your desktop -- :material-docker: **[Docker Setup](User%20Guide/docker.md)** +- :material-server: **[Server Installation](User%20Guide/User%20Guide/Installation%20%26%20Setup/Server%20Installation.md)** - Deploy Trilium using Docker containers + Deploy Trilium as a server -- :material-book-open-variant: **[User Guide](User%20Guide/index.md)** +- :material-book-open-variant: **[User Guide](User%20Guide/User%20Guide.md)** Comprehensive guide to all features -- :material-code-braces: **[Script API](Script%20API/index.md)** +- :material-code-braces: **[Script API](Script%20API/index.html)** Automate and extend Trilium with scripting -- :material-wrench: **[Developer Guide](Developer%20Guide/index.md)** +- :material-wrench: **[Developer Guide](Developer%20Guide/Developer%20Guide/Environment%20Setup.md)** Contributing and development documentation @@ -80,14 +80,14 @@ Trilium Notes is a powerful, feature-rich note-taking application designed for b ## Getting Help -- **[FAQ](support/faq.md)** - Frequently asked questions -- **[Troubleshooting](support/troubleshooting.md)** - Common issues and solutions +- **[FAQ](User%20Guide/User%20Guide/FAQ.md)** - Frequently asked questions +- **[Troubleshooting](User%20Guide/User%20Guide/Troubleshooting.md)** - Common issues and solutions - **[Community Forum](https://github.com/triliumnext/trilium/discussions)** - Ask questions and share tips - **[Issue Tracker](https://github.com/triliumnext/trilium/issues)** - Report bugs and request features ## Contributing -Trilium is open-source and welcomes contributions! Check out our [Contributing Guide](Developer%20Guide/contributing.md) to get started. +Trilium is open-source and welcomes contributions! Check out our [GitHub repository](https://github.com/triliumnext/trilium) to get started. ## License diff --git a/package.json b/package.json index e27962d2f..402997ce5 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "chore:update-build-info": "tsx ./scripts/update-build-info.ts", "chore:update-version": "tsx ./scripts/update-version.ts", "docs:build": "pnpm run --filter build-docs start", + "docs:preview": "pnpm http-server site -p 9000", "edit-docs:edit-docs": "pnpm run --filter edit-docs edit-docs", "edit-docs:edit-demo": "pnpm run --filter edit-docs edit-demo", "test:all": "pnpm test:parallel && pnpm test:sequential", @@ -49,11 +50,12 @@ "cross-env": "10.1.0", "dpdm": "3.14.0", "esbuild": "0.25.12", - "eslint": "9.39.0", + "eslint": "9.39.1", "eslint-config-prettier": "10.1.8", "eslint-plugin-playwright": "2.3.0", "eslint-plugin-react-hooks": "7.0.1", "happy-dom": "~20.0.0", + "http-server": "14.1.1", "jiti": "2.6.1", "jsonc-eslint-parser": "2.4.1", "react-refresh": "0.18.0", @@ -61,7 +63,7 @@ "tslib": "2.8.1", "tsx": "4.20.6", "typescript": "~5.9.0", - "typescript-eslint": "8.46.2", + "typescript-eslint": "8.46.3", "upath": "2.0.1", "vite": "7.1.12", "vite-plugin-dts": "~4.5.0", diff --git a/packages/ckeditor5-admonition/package.json b/packages/ckeditor5-admonition/package.json index bc32ffc98..7b75a79ba 100644 --- a/packages/ckeditor5-admonition/package.json +++ b/packages/ckeditor5-admonition/package.json @@ -25,11 +25,11 @@ "@ckeditor/ckeditor5-inspector": ">=4.1.0", "@ckeditor/ckeditor5-package-tools": "4.1.1", "@typescript-eslint/eslint-plugin": "~8.46.0", - "@typescript-eslint/parser": "8.46.2", + "@typescript-eslint/parser": "8.46.3", "@vitest/browser": "3.2.4", "@vitest/coverage-istanbul": "3.2.4", "ckeditor5": "47.1.0", - "eslint": "9.39.0", + "eslint": "9.39.1", "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.6", diff --git a/packages/ckeditor5-footnotes/package.json b/packages/ckeditor5-footnotes/package.json index 2835113b1..d3fdac60a 100644 --- a/packages/ckeditor5-footnotes/package.json +++ b/packages/ckeditor5-footnotes/package.json @@ -26,11 +26,11 @@ "@ckeditor/ckeditor5-inspector": ">=4.1.0", "@ckeditor/ckeditor5-package-tools": "4.1.1", "@typescript-eslint/eslint-plugin": "~8.46.0", - "@typescript-eslint/parser": "8.46.2", + "@typescript-eslint/parser": "8.46.3", "@vitest/browser": "3.2.4", "@vitest/coverage-istanbul": "3.2.4", "ckeditor5": "47.1.0", - "eslint": "9.39.0", + "eslint": "9.39.1", "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.6", diff --git a/packages/ckeditor5-keyboard-marker/package.json b/packages/ckeditor5-keyboard-marker/package.json index cfbef699b..69f9ee4cf 100644 --- a/packages/ckeditor5-keyboard-marker/package.json +++ b/packages/ckeditor5-keyboard-marker/package.json @@ -28,11 +28,11 @@ "@ckeditor/ckeditor5-inspector": ">=4.1.0", "@ckeditor/ckeditor5-package-tools": "4.1.1", "@typescript-eslint/eslint-plugin": "~8.46.0", - "@typescript-eslint/parser": "8.46.2", + "@typescript-eslint/parser": "8.46.3", "@vitest/browser": "3.2.4", "@vitest/coverage-istanbul": "3.2.4", "ckeditor5": "47.1.0", - "eslint": "9.39.0", + "eslint": "9.39.1", "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.6", diff --git a/packages/ckeditor5-math/package.json b/packages/ckeditor5-math/package.json index 97573e4aa..85d1358cc 100644 --- a/packages/ckeditor5-math/package.json +++ b/packages/ckeditor5-math/package.json @@ -29,11 +29,11 @@ "@ckeditor/ckeditor5-inspector": ">=4.1.0", "@ckeditor/ckeditor5-package-tools": "4.1.1", "@typescript-eslint/eslint-plugin": "~8.46.0", - "@typescript-eslint/parser": "8.46.2", + "@typescript-eslint/parser": "8.46.3", "@vitest/browser": "3.2.4", "@vitest/coverage-istanbul": "3.2.4", "ckeditor5": "47.1.0", - "eslint": "9.39.0", + "eslint": "9.39.1", "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.6", diff --git a/packages/ckeditor5-mermaid/package.json b/packages/ckeditor5-mermaid/package.json index c924a95b6..f83566bc4 100644 --- a/packages/ckeditor5-mermaid/package.json +++ b/packages/ckeditor5-mermaid/package.json @@ -28,11 +28,11 @@ "@ckeditor/ckeditor5-inspector": ">=4.1.0", "@ckeditor/ckeditor5-package-tools": "4.1.1", "@typescript-eslint/eslint-plugin": "~8.46.0", - "@typescript-eslint/parser": "8.46.2", + "@typescript-eslint/parser": "8.46.3", "@vitest/browser": "3.2.4", "@vitest/coverage-istanbul": "3.2.4", "ckeditor5": "47.1.0", - "eslint": "9.39.0", + "eslint": "9.39.1", "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.6", diff --git a/packages/codemirror/package.json b/packages/codemirror/package.json index dfb44d686..7bdc83796 100644 --- a/packages/codemirror/package.json +++ b/packages/codemirror/package.json @@ -50,6 +50,6 @@ "codemirror-lang-elixir": "4.0.0", "codemirror-lang-hcl": "0.1.0", "codemirror-lang-mermaid": "0.5.0", - "eslint-linter-browserify": "9.39.0" + "eslint-linter-browserify": "9.39.1" } } diff --git a/packages/share-theme/package.json b/packages/share-theme/package.json index 1fd56501e..fbd289fbc 100644 --- a/packages/share-theme/package.json +++ b/packages/share-theme/package.json @@ -32,11 +32,11 @@ "devDependencies": { "@digitak/esrun": "3.2.26", "@triliumnext/ckeditor5": "workspace:*", - "@typescript-eslint/eslint-plugin": "8.46.2", - "@typescript-eslint/parser": "8.46.2", + "@typescript-eslint/eslint-plugin": "8.46.3", + "@typescript-eslint/parser": "8.46.3", "dotenv": "17.2.3", "esbuild": "0.25.12", - "eslint": "9.39.0", + "eslint": "9.39.1", "highlight.js": "11.11.1", "typescript": "5.9.3" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98c93f61d..c016b4c2f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,20 +74,23 @@ importers: specifier: 0.25.12 version: 0.25.12 eslint: - specifier: 9.39.0 - version: 9.39.0(jiti@2.6.1) + specifier: 9.39.1 + version: 9.39.1(jiti@2.6.1) eslint-config-prettier: specifier: 10.1.8 - version: 10.1.8(eslint@9.39.0(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-playwright: specifier: 2.3.0 - version: 2.3.0(eslint@9.39.0(jiti@2.6.1)) + version: 2.3.0(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-react-hooks: specifier: 7.0.1 - version: 7.0.1(eslint@9.39.0(jiti@2.6.1)) + version: 7.0.1(eslint@9.39.1(jiti@2.6.1)) happy-dom: specifier: ~20.0.0 version: 20.0.10 + http-server: + specifier: 14.1.1 + version: 14.1.1 jiti: specifier: 2.6.1 version: 2.6.1 @@ -110,8 +113,8 @@ importers: specifier: ~5.9.0 version: 5.9.3 typescript-eslint: - specifier: 8.46.2 - version: 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.46.3 + version: 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) upath: specifier: 2.0.1 version: 2.0.1 @@ -128,8 +131,8 @@ importers: apps/build-docs: devDependencies: '@redocly/cli': - specifier: 2.10.0 - version: 2.10.0(@opentelemetry/api@1.9.0)(ajv@8.17.1)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5) + specifier: 2.11.0 + version: 2.11.0(@opentelemetry/api@1.9.0)(ajv@8.17.1)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5) archiver: specifier: 7.0.1 version: 7.0.1 @@ -152,8 +155,8 @@ importers: apps/client: dependencies: '@eslint/js': - specifier: 9.39.0 - version: 9.39.0 + specifier: 9.39.1 + version: 9.39.1 '@excalidraw/excalidraw': specifier: 0.18.0 version: 0.18.0(@types/react-dom@19.1.6(@types/react@19.1.7))(@types/react@19.1.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -284,8 +287,8 @@ importers: specifier: 10.27.2 version: 10.27.2 react-i18next: - specifier: 16.2.3 - version: 16.2.3(i18next@25.6.0(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + specifier: 16.2.4 + version: 16.2.4(i18next@25.6.0(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3) reveal.js: specifier: 5.2.1 version: 5.2.1 @@ -601,8 +604,8 @@ importers: specifier: 0.5.0 version: 0.5.0 axios: - specifier: 1.13.1 - version: 1.13.1(debug@4.4.3) + specifier: 1.13.2 + version: 1.13.2(debug@4.4.3) bindings: specifier: 1.5.0 version: 1.5.0 @@ -730,8 +733,8 @@ importers: specifier: 0.6.2 version: 0.6.2 openai: - specifier: 6.7.0 - version: 6.7.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@4.1.12) + specifier: 6.8.0 + version: 6.8.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@4.1.12) rand-token: specifier: 1.0.1 version: 1.0.1 @@ -745,8 +748,8 @@ importers: specifier: 2.17.0 version: 2.17.0 sax: - specifier: 1.4.1 - version: 1.4.1 + specifier: 1.4.3 + version: 1.4.3 serve-favicon: specifier: 2.5.1 version: 2.5.1 @@ -814,18 +817,18 @@ importers: specifier: 6.6.3 version: 6.6.3(preact@10.27.2) react-i18next: - specifier: 16.2.3 - version: 16.2.3(i18next@25.6.0(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + specifier: 16.2.4 + version: 16.2.4(i18next@25.6.0(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3) devDependencies: '@preact/preset-vite': specifier: 2.10.2 version: 2.10.2(@babel/core@7.28.0)(preact@10.27.2)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) eslint: - specifier: 9.39.0 - version: 9.39.0(jiti@2.6.1) + specifier: 9.39.1 + version: 9.39.1(jiti@2.6.1) eslint-config-preact: specifier: 2.0.0 - version: 2.0.0(eslint@9.39.0(jiti@2.6.1)) + version: 2.0.0(eslint@9.39.1(jiti@2.6.1)) typescript: specifier: 5.9.3 version: 5.9.3 @@ -880,10 +883,10 @@ importers: version: 4.1.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.0)(bufferutil@4.0.9)(esbuild@0.25.12)(utf-8-validate@6.0.5) '@typescript-eslint/eslint-plugin': specifier: ~8.46.0 - version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.46.2 - version: 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.46.3 + version: 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': specifier: 3.2.4 version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.0)(typescript@5.9.3))(playwright@1.56.1)(utf-8-validate@6.0.5)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) @@ -894,11 +897,11 @@ importers: specifier: 47.1.0 version: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) eslint: - specifier: 9.39.0 - version: 9.39.0(jiti@2.6.1) + specifier: 9.39.1 + version: 9.39.1(jiti@2.6.1) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.2.0(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + version: 12.2.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) http-server: specifier: 14.1.1 version: 14.1.1 @@ -940,10 +943,10 @@ importers: version: 4.1.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.0)(bufferutil@4.0.9)(esbuild@0.25.12)(utf-8-validate@6.0.5) '@typescript-eslint/eslint-plugin': specifier: ~8.46.0 - version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.46.2 - version: 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.46.3 + version: 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': specifier: 3.2.4 version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.0)(typescript@5.9.3))(playwright@1.56.1)(utf-8-validate@6.0.5)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) @@ -954,11 +957,11 @@ importers: specifier: 47.1.0 version: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) eslint: - specifier: 9.39.0 - version: 9.39.0(jiti@2.6.1) + specifier: 9.39.1 + version: 9.39.1(jiti@2.6.1) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.2.0(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + version: 12.2.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) http-server: specifier: 14.1.1 version: 14.1.1 @@ -1000,10 +1003,10 @@ importers: version: 4.1.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.0)(bufferutil@4.0.9)(esbuild@0.25.12)(utf-8-validate@6.0.5) '@typescript-eslint/eslint-plugin': specifier: ~8.46.0 - version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.46.2 - version: 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.46.3 + version: 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': specifier: 3.2.4 version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.0)(typescript@5.9.3))(playwright@1.56.1)(utf-8-validate@6.0.5)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) @@ -1014,11 +1017,11 @@ importers: specifier: 47.1.0 version: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) eslint: - specifier: 9.39.0 - version: 9.39.0(jiti@2.6.1) + specifier: 9.39.1 + version: 9.39.1(jiti@2.6.1) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.2.0(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + version: 12.2.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) http-server: specifier: 14.1.1 version: 14.1.1 @@ -1067,10 +1070,10 @@ importers: version: 4.1.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.0)(bufferutil@4.0.9)(esbuild@0.25.12)(utf-8-validate@6.0.5) '@typescript-eslint/eslint-plugin': specifier: ~8.46.0 - version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.46.2 - version: 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.46.3 + version: 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': specifier: 3.2.4 version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.0)(typescript@5.9.3))(playwright@1.56.1)(utf-8-validate@6.0.5)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) @@ -1081,11 +1084,11 @@ importers: specifier: 47.1.0 version: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) eslint: - specifier: 9.39.0 - version: 9.39.0(jiti@2.6.1) + specifier: 9.39.1 + version: 9.39.1(jiti@2.6.1) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.2.0(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + version: 12.2.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) http-server: specifier: 14.1.1 version: 14.1.1 @@ -1134,10 +1137,10 @@ importers: version: 4.1.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.0)(bufferutil@4.0.9)(esbuild@0.25.12)(utf-8-validate@6.0.5) '@typescript-eslint/eslint-plugin': specifier: ~8.46.0 - version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.46.2 - version: 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.46.3 + version: 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitest/browser': specifier: 3.2.4 version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.0)(typescript@5.9.3))(playwright@1.56.1)(utf-8-validate@6.0.5)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) @@ -1148,11 +1151,11 @@ importers: specifier: 47.1.0 version: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) eslint: - specifier: 9.39.0 - version: 9.39.0(jiti@2.6.1) + specifier: 9.39.1 + version: 9.39.1(jiti@2.6.1) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.2.0(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + version: 12.2.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) http-server: specifier: 14.1.1 version: 14.1.1 @@ -1319,8 +1322,8 @@ importers: specifier: 0.5.0 version: 0.5.0 eslint-linter-browserify: - specifier: 9.39.0 - version: 9.39.0 + specifier: 9.39.1 + version: 9.39.1 packages/commons: {} @@ -1370,11 +1373,11 @@ importers: specifier: workspace:* version: link:../ckeditor5 '@typescript-eslint/eslint-plugin': - specifier: 8.46.2 - version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.46.3 + version: 8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: 8.46.2 - version: 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.46.3 + version: 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) dotenv: specifier: 17.2.3 version: 17.2.3 @@ -1382,8 +1385,8 @@ importers: specifier: 0.25.12 version: 0.25.12 eslint: - specifier: 9.39.0 - version: 9.39.0(jiti@2.6.1) + specifier: 9.39.1 + version: 9.39.1(jiti@2.6.1) highlight.js: specifier: 11.11.1 version: 11.11.1 @@ -2304,11 +2307,11 @@ packages: engines: {node: '>=14.14'} hasBin: true - '@emnapi/core@1.6.0': - resolution: {integrity: sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg==} + '@emnapi/core@1.7.0': + resolution: {integrity: sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw==} - '@emnapi/runtime@1.6.0': - resolution: {integrity: sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==} + '@emnapi/runtime@1.7.0': + resolution: {integrity: sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} @@ -2807,6 +2810,10 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint/config-array@0.21.1': resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2831,8 +2838,8 @@ packages: resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.0': - resolution: {integrity: sha512-BIhe0sW91JGPiaF1mOuPy5v8NflqfjIcDNpC+LbW9f609WVRX1rArrhi6Z2ymvrAry9jw+5POTj4t2t62o8Bmw==} + '@eslint/js@9.39.1': + resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/markdown@6.6.0': @@ -4216,27 +4223,27 @@ packages: '@redocly/ajv@8.11.3': resolution: {integrity: sha512-4P3iZse91TkBiY+Dx5DUgxQ9GXkVJf++cmI0MOyLDxV9b5MUBI4II6ES8zA5JCbO72nKAJxWrw4PUPW+YP3ZDQ==} - '@redocly/cli@2.10.0': - resolution: {integrity: sha512-wKuF/30MSmcc4SJwWTuVnIeFKyW60DVOgxTzvvA+wC1HRBZ24X3UTRyt6MtDEFGcNl6hv5/J9l2lodStwwqelQ==} + '@redocly/cli@2.11.0': + resolution: {integrity: sha512-Wr8me9M5tQ4pZT7Z0Llxojlo8L0GBBt45zceQ8iKyBmJUHWDbKYYdKubZBCH0XktQLEA8HitYBGN1unsxwx20g==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} hasBin: true '@redocly/config@0.22.2': resolution: {integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==} - '@redocly/config@0.36.2': - resolution: {integrity: sha512-gwIjFOzyq9bdJCdtEHDMf2hEJ9hHXUHkY1U3IPWyZmRoFcibzlpXOLrT0xVgnn10IEttMwD+SZtZBE593yDXsw==} + '@redocly/config@0.37.0': + resolution: {integrity: sha512-cYN+rTTCQIp5mVt1xumJsNqpZcaPVUf1x0ryD0QKXpVKsxKc+lHaMF2P1CqMgdQNY9B7i84z/kvxD0EhxzlxbQ==} '@redocly/openapi-core@1.34.5': resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} - '@redocly/openapi-core@2.10.0': - resolution: {integrity: sha512-OmWvnpA11J6Tp3+h8I3nrfpTcXROLllr/9yIUB7ofi7s1yOOKOqlZ4HTs+zaeNmk9vclwmbgc2HVdSsBKUXp6g==} + '@redocly/openapi-core@2.11.0': + resolution: {integrity: sha512-CF4QpCoxxHIB7Dib1XnhdL0WuW4dO4zvNfaEWpN7TASlitOX2mhrc6sD3dYG9knW1iG16e3Oauv2O+tVJx1E9Q==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} - '@redocly/respect-core@2.10.0': - resolution: {integrity: sha512-4XFOR3kbuhlPBeW2G/G3yPs7YJKV0d/k2BgDwKIQH8Edld4fHvknEAR9TFUaWsiA7JGWrP3CQ58P5VoDNW5O0Q==} + '@redocly/respect-core@2.11.0': + resolution: {integrity: sha512-lAvDILvq82IIei2gVyapGyfuWEamJgCiGO++yQriVk4Wr0hE3lF7ZWusUM3aGZrxEWCVGeeLwbMBpv1BQOnmEg==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} '@replit/codemirror-indentation-markers@6.5.3': @@ -5628,6 +5635,14 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/eslint-plugin@8.46.3': + resolution: {integrity: sha512-sbaQ27XBUopBkRiuY/P9sWGOWUW4rl8fDoHIUmLpZd8uldsTyB4/Zg6bWTegPoTLnKj9Hqgn3QD6cjPNB32Odw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.46.3 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/parser@8.46.2': resolution: {integrity: sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5635,22 +5650,45 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/parser@8.46.3': + resolution: {integrity: sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/project-service@8.46.2': resolution: {integrity: sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/project-service@8.46.3': + resolution: {integrity: sha512-Fz8yFXsp2wDFeUElO88S9n4w1I4CWDTXDqDr9gYvZgUpwXQqmZBr9+NTTql5R3J7+hrJZPdpiWaB9VNhAKYLuQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/scope-manager@8.46.2': resolution: {integrity: sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.46.3': + resolution: {integrity: sha512-FCi7Y1zgrmxp3DfWfr+3m9ansUUFoy8dkEdeQSgA9gbm8DaHYvZCdkFRQrtKiedFf3Ha6VmoqoAaP68+i+22kg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/tsconfig-utils@8.46.2': resolution: {integrity: sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/tsconfig-utils@8.46.3': + resolution: {integrity: sha512-GLupljMniHNIROP0zE7nCcybptolcH8QZfXOpCfhQDAdwJ/ZTlcaBOYebSOZotpti/3HrHSw7D3PZm75gYFsOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/type-utils@8.46.2': resolution: {integrity: sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5658,16 +5696,33 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/type-utils@8.46.3': + resolution: {integrity: sha512-ZPCADbr+qfz3aiTTYNNkCbUt+cjNwI/5McyANNrFBpVxPt7GqpEYz5ZfdwuFyGUnJ9FdDXbGODUu6iRCI6XRXw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/types@8.46.2': resolution: {integrity: sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.46.3': + resolution: {integrity: sha512-G7Ok9WN/ggW7e/tOf8TQYMaxgID3Iujn231hfi0Pc7ZheztIJVpO44ekY00b7akqc6nZcvregk0Jpah3kep6hA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.46.2': resolution: {integrity: sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/typescript-estree@8.46.3': + resolution: {integrity: sha512-f/NvtRjOm80BtNM5OQtlaBdM5BRFUv7gf381j9wygDNL+qOYSNOgtQ/DCndiYi80iIOv76QqaTmp4fa9hwI0OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/utils@8.46.2': resolution: {integrity: sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5675,10 +5730,21 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/utils@8.46.3': + resolution: {integrity: sha512-VXw7qmdkucEx9WkmR3ld/u6VhRyKeiF1uxWwCy/iuNfokjJ7VhsgLSOTjsol8BunSw190zABzpwdNsze2Kpo4g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/visitor-keys@8.46.2': resolution: {integrity: sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.46.3': + resolution: {integrity: sha512-uk574k8IU0rOF/AjniX8qbLSGURJVUCeM5e4MIMKBFFi8weeiLrG1fyQejyLXQpRZbU/1BuQasleV/RfHC3hHg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} @@ -6229,8 +6295,8 @@ packages: resolution: {integrity: sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==} engines: {node: '>=6.0.0'} - axios@1.13.1: - resolution: {integrity: sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==} + axios@1.13.2: + resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} b4a@1.6.7: resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} @@ -8013,8 +8079,8 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-linter-browserify@9.39.0: - resolution: {integrity: sha512-SmFk1DwXcC+p2IjHAouYjjJcAKAiSMlMrJgc8w2s1W3D00FM2sC6SHeCd8Axy1T5sB8oMVMt23GuCun8/UFo1Q==} + eslint-linter-browserify@9.39.1: + resolution: {integrity: sha512-XdoocZkDVe9svpVe1V9q0cW3pufacQ0z7Unhu4E4AaeHHxF4AZa5+HRHYMKO30NUKEQfDv+ITibXUNi1C6QGbQ==} eslint-plugin-ckeditor5-rules@12.2.0: resolution: {integrity: sha512-WgQP9aZo1N7bIDwwf2Wsnd0RpL20MAVxEehhYoFWy7HAMAnV3IliKuU3dsFA35O8cK4q7eKz7FiObwSRAfttQA==} @@ -8074,8 +8140,8 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.39.0: - resolution: {integrity: sha512-iy2GE3MHrYTL5lrCtMZ0X1KLEKKUjmK0kzwcnefhR66txcEmXZD2YWgR5GNdcEwkNx3a0siYkSvl0vIC+Svjmg==} + eslint@9.39.1: + resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -10928,8 +10994,8 @@ packages: resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} engines: {node: '>=18'} - openai@6.7.0: - resolution: {integrity: sha512-mgSQXa3O/UXTbA8qFzoa7aydbXBJR5dbLQXCRapAOtoNT+v69sLdKMZzgiakpqhclRnhPggPAXoniVGn2kMY2A==} + openai@6.8.0: + resolution: {integrity: sha512-GQUpzb9FoNkh1wqJuDIQ8e/Sq8dW+T3GakG6wJTXBE8Lufx1GaUcgZd087vhm8f/MiOzsTEkfRamYxzJ/jOoiw==} hasBin: true peerDependencies: ws: ^8.18.0 @@ -12320,8 +12386,8 @@ packages: peerDependencies: react: ^19.2.0 - react-i18next@16.2.3: - resolution: {integrity: sha512-O0t2zvmIz7nHWKNfIL+O/NTIbpTaOPY0vZov779hegbep3IZ+xcqkeVPKWBSXwzdkiv77q8zmq9toKIUys1x3A==} + react-i18next@16.2.4: + resolution: {integrity: sha512-pvbcPQ+YuQQoRkKBA4VCU9aO8dOgP/vdKEizIYXcAk3+AmI8yQKSJaCzxQQu4Kgg2zWZm3ax9KqHv8ItUlRY0A==} peerDependencies: i18next: '>= 25.5.2' react: '>= 16.8.0' @@ -12879,8 +12945,8 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - sax@1.4.1: - resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + sax@1.4.3: + resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} saxes@5.0.1: resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} @@ -13993,6 +14059,13 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + typescript-eslint@8.46.3: + resolution: {integrity: sha512-bAfgMavTuGo+8n6/QQDVQz4tZ4f7Soqg53RbrlZQEoAltYop/XR4RAts/I0BrO3TTClTSTFJ0wYbla+P8cEWJA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + typescript@5.0.4: resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} engines: {node: '>=12.20'} @@ -15328,11 +15401,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/eslint-parser@7.28.4(@babel/core@7.28.0)(eslint@9.39.0(jiti@2.6.1))': + '@babel/eslint-parser@7.28.4(@babel/core@7.28.0)(eslint@9.39.1(jiti@2.6.1))': dependencies: '@babel/core': 7.28.0 '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) eslint-visitor-keys: 2.1.0 semver: 6.3.1 @@ -15538,6 +15611,8 @@ snapshots: '@ckeditor/ckeditor5-core': 47.1.0 '@ckeditor/ckeditor5-upload': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-ai@47.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -15684,8 +15759,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.1.0 '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-code-block@47.1.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)': dependencies: @@ -15922,6 +15995,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-decoupled@47.1.0': dependencies: @@ -15931,6 +16006,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-inline@47.1.0': dependencies: @@ -15940,8 +16017,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-multi-root@47.1.0': dependencies: @@ -16048,6 +16123,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-font@47.1.0': dependencies: @@ -16111,6 +16188,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.1.0 '@ckeditor/ckeditor5-widget': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-html-embed@47.1.0': dependencies: @@ -16401,6 +16480,8 @@ snapshots: '@ckeditor/ckeditor5-paste-from-office': 47.1.0 '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-paste-from-office@47.1.0': dependencies: @@ -16408,6 +16489,8 @@ snapshots: '@ckeditor/ckeditor5-core': 47.1.0 '@ckeditor/ckeditor5-engine': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-real-time-collaboration@47.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -16438,6 +16521,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.1.0 '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-restricted-editing@47.1.0': dependencies: @@ -16447,6 +16532,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.1.0 '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-revision-history@47.1.0': dependencies: @@ -16524,6 +16611,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.1.0 '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-special-characters@47.1.0': dependencies: @@ -16533,6 +16622,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.1.0 '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-style@47.1.0': dependencies: @@ -16635,6 +16726,8 @@ snapshots: '@ckeditor/ckeditor5-icons': 47.1.0 '@ckeditor/ckeditor5-ui': 47.1.0 '@ckeditor/ckeditor5-utils': 47.1.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-upload@47.1.0': dependencies: @@ -17308,13 +17401,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@emnapi/core@1.6.0': + '@emnapi/core@1.7.0': dependencies: '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.6.0': + '@emnapi/runtime@1.7.0': dependencies: tslib: 2.8.1 optional: true @@ -17337,7 +17430,7 @@ snapshots: '@es-joy/jsdoccomment@0.50.2': dependencies: '@types/estree': 1.0.8 - '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/types': 8.46.3 comment-parser: 1.4.1 esquery: 1.6.0 jsdoc-type-pratt-parser: 4.1.0 @@ -17576,13 +17669,15 @@ snapshots: '@esbuild/win32-x64@0.25.12': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.0(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': dependencies: - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} + '@eslint-community/regexpp@4.12.2': {} + '@eslint/config-array@0.21.1': dependencies: '@eslint/object-schema': 2.1.7 @@ -17621,7 +17716,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.39.0': {} + '@eslint/js@9.39.1': {} '@eslint/markdown@6.6.0': dependencies: @@ -17720,7 +17815,7 @@ snapshots: '@file-type/xml@0.4.3': dependencies: - sax: 1.4.1 + sax: 1.4.3 strtok3: 10.2.2 '@floating-ui/core@1.6.9': @@ -18593,8 +18688,8 @@ snapshots: '@napi-rs/wasm-runtime@1.0.7': dependencies: - '@emnapi/core': 1.6.0 - '@emnapi/runtime': 1.6.0 + '@emnapi/core': 1.7.0 + '@emnapi/runtime': 1.7.0 '@tybys/wasm-util': 0.10.1 optional: true @@ -19247,14 +19342,14 @@ snapshots: require-from-string: 2.0.2 uri-js-replace: 1.0.1 - '@redocly/cli@2.10.0(@opentelemetry/api@1.9.0)(ajv@8.17.1)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)': + '@redocly/cli@2.11.0(@opentelemetry/api@1.9.0)(ajv@8.17.1)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)': dependencies: '@opentelemetry/exporter-trace-otlp-http': 0.202.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.34.0 - '@redocly/openapi-core': 2.10.0(ajv@8.17.1) - '@redocly/respect-core': 2.10.0(ajv@8.17.1) + '@redocly/openapi-core': 2.11.0(ajv@8.17.1) + '@redocly/respect-core': 2.11.0(ajv@8.17.1) abort-controller: 3.0.0 chokidar: 3.6.0 colorette: 1.4.0 @@ -19287,7 +19382,7 @@ snapshots: '@redocly/config@0.22.2': {} - '@redocly/config@0.36.2': + '@redocly/config@0.37.0': dependencies: json-schema-to-ts: 2.7.2 @@ -19305,10 +19400,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@redocly/openapi-core@2.10.0(ajv@8.17.1)': + '@redocly/openapi-core@2.11.0(ajv@8.17.1)': dependencies: '@redocly/ajv': 8.11.3 - '@redocly/config': 0.36.2 + '@redocly/config': 0.37.0 ajv-formats: 2.1.1(ajv@8.17.1) colorette: 1.4.0 js-levenshtein: 1.1.6 @@ -19319,12 +19414,12 @@ snapshots: transitivePeerDependencies: - ajv - '@redocly/respect-core@2.10.0(ajv@8.17.1)': + '@redocly/respect-core@2.11.0(ajv@8.17.1)': dependencies: '@faker-js/faker': 7.6.0 '@noble/hashes': 1.8.0 '@redocly/ajv': 8.11.2 - '@redocly/openapi-core': 2.10.0(ajv@8.17.1) + '@redocly/openapi-core': 2.11.0(ajv@8.17.1) better-ajv-errors: 1.2.0(ajv@8.17.1) colorette: 2.0.20 json-pointer: 0.6.2 @@ -20170,10 +20265,10 @@ snapshots: '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 - '@stylistic/eslint-plugin@4.4.1(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': + '@stylistic/eslint-plugin@4.4.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.0(jiti@2.6.1) + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 @@ -20869,15 +20964,15 @@ snapshots: '@types/node': 24.10.0 optional: true - '@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.46.2 - '@typescript-eslint/type-utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.46.2 - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -20886,14 +20981,43 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.46.3 + '@typescript-eslint/type-utils': 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.3 + eslint: 9.39.1(jiti@2.6.1) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.46.2 '@typescript-eslint/types': 8.46.2 '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.46.2 debug: 4.4.3(supports-color@6.0.0) - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.46.3 + '@typescript-eslint/types': 8.46.3 + '@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.3 + debug: 4.4.3(supports-color@6.0.0) + eslint: 9.39.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -20907,22 +21031,52 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.46.3(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.3(typescript@5.9.3) + '@typescript-eslint/types': 8.46.3 + debug: 4.4.3(supports-color@6.0.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.46.2': dependencies: '@typescript-eslint/types': 8.46.2 '@typescript-eslint/visitor-keys': 8.46.2 + '@typescript-eslint/scope-manager@8.46.3': + dependencies: + '@typescript-eslint/types': 8.46.3 + '@typescript-eslint/visitor-keys': 8.46.3 + '@typescript-eslint/tsconfig-utils@8.46.2(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.46.3(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.46.2 '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3(supports-color@6.0.0) - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/type-utils@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.46.3 + '@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3(supports-color@6.0.0) + eslint: 9.39.1(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -20930,6 +21084,8 @@ snapshots: '@typescript-eslint/types@8.46.2': {} + '@typescript-eslint/types@8.46.3': {} + '@typescript-eslint/typescript-estree@8.46.2(typescript@5.9.3)': dependencies: '@typescript-eslint/project-service': 8.46.2(typescript@5.9.3) @@ -20946,13 +21102,40 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.46.3(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) + '@typescript-eslint/project-service': 8.46.3(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.46.3(typescript@5.9.3) + '@typescript-eslint/types': 8.46.3 + '@typescript-eslint/visitor-keys': 8.46.3 + debug: 4.4.3(supports-color@6.0.0) + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) '@typescript-eslint/scope-manager': 8.46.2 '@typescript-eslint/types': 8.46.2 '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.46.3 + '@typescript-eslint/types': 8.46.3 + '@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -20962,6 +21145,11 @@ snapshots: '@typescript-eslint/types': 8.46.2 eslint-visitor-keys: 4.2.1 + '@typescript-eslint/visitor-keys@8.46.3': + dependencies: + '@typescript-eslint/types': 8.46.3 + eslint-visitor-keys: 4.2.1 + '@ungap/structured-clone@1.3.0': {} '@uploadcare/cname-prefix@6.17.0': {} @@ -21652,7 +21840,7 @@ snapshots: await-to-js@3.0.0: {} - axios@1.13.1(debug@4.4.3): + axios@1.13.2(debug@4.4.3): dependencies: follow-redirects: 1.15.9(debug@4.4.3) form-data: 4.0.4 @@ -24032,40 +24220,40 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-ckeditor5@12.2.0(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3): + eslint-config-ckeditor5@12.2.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@eslint/js': 9.39.0 + '@eslint/js': 9.39.1 '@eslint/markdown': 6.6.0 - '@stylistic/eslint-plugin': 4.4.1(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.0(jiti@2.6.1) + '@stylistic/eslint-plugin': 4.4.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) eslint-plugin-ckeditor5-rules: 12.2.0 - eslint-plugin-mocha: 11.2.0(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-mocha: 11.2.0(eslint@9.39.1(jiti@2.6.1)) globals: 16.5.0 typescript: 5.9.3 - typescript-eslint: 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + typescript-eslint: 8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - supports-color - eslint-config-preact@2.0.0(eslint@9.39.0(jiti@2.6.1)): + eslint-config-preact@2.0.0(eslint@9.39.1(jiti@2.6.1)): dependencies: '@babel/core': 7.28.0 - '@babel/eslint-parser': 7.28.4(@babel/core@7.28.0)(eslint@9.39.0(jiti@2.6.1)) + '@babel/eslint-parser': 7.28.4(@babel/core@7.28.0)(eslint@9.39.1(jiti@2.6.1)) '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.0) '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) - '@eslint/js': 9.39.0 - eslint: 9.39.0(jiti@2.6.1) - eslint-plugin-compat: 6.0.2(eslint@9.39.0(jiti@2.6.1)) - eslint-plugin-react: 7.37.5(eslint@9.39.0(jiti@2.6.1)) - eslint-plugin-react-hooks: 5.2.0(eslint@9.39.0(jiti@2.6.1)) + '@eslint/js': 9.39.1 + eslint: 9.39.1(jiti@2.6.1) + eslint-plugin-compat: 6.0.2(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@2.6.1)) globals: 16.5.0 transitivePeerDependencies: - supports-color - eslint-config-prettier@10.1.8(eslint@9.39.0(jiti@2.6.1)): + eslint-config-prettier@10.1.8(eslint@9.39.1(jiti@2.6.1)): dependencies: - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) - eslint-linter-browserify@9.39.0: {} + eslint-linter-browserify@9.39.1: {} eslint-plugin-ckeditor5-rules@12.2.0: dependencies: @@ -24077,45 +24265,45 @@ snapshots: validate-npm-package-name: 6.0.2 yaml: 2.8.1 - eslint-plugin-compat@6.0.2(eslint@9.39.0(jiti@2.6.1)): + eslint-plugin-compat@6.0.2(eslint@9.39.1(jiti@2.6.1)): dependencies: '@mdn/browser-compat-data': 5.7.6 ast-metadata-inferer: 0.8.1 browserslist: 4.26.2 caniuse-lite: 1.0.30001743 - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) find-up: 5.0.0 globals: 15.15.0 lodash.memoize: 4.1.2 semver: 7.7.2 - eslint-plugin-mocha@11.2.0(eslint@9.39.0(jiti@2.6.1)): + eslint-plugin-mocha@11.2.0(eslint@9.39.1(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) - eslint: 9.39.0(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + eslint: 9.39.1(jiti@2.6.1) globals: 15.15.0 - eslint-plugin-playwright@2.3.0(eslint@9.39.0(jiti@2.6.1)): + eslint-plugin-playwright@2.3.0(eslint@9.39.1(jiti@2.6.1)): dependencies: - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) globals: 16.5.0 - eslint-plugin-react-hooks@5.2.0(eslint@9.39.0(jiti@2.6.1)): + eslint-plugin-react-hooks@5.2.0(eslint@9.39.1(jiti@2.6.1)): dependencies: - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) - eslint-plugin-react-hooks@7.0.1(eslint@9.39.0(jiti@2.6.1)): + eslint-plugin-react-hooks@7.0.1(eslint@9.39.1(jiti@2.6.1)): dependencies: '@babel/core': 7.28.0 '@babel/parser': 7.28.4 - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) hermes-parser: 0.25.1 zod: 4.1.12 zod-validation-error: 3.5.3(zod@4.1.12) transitivePeerDependencies: - supports-color - eslint-plugin-react@7.37.5(eslint@9.39.0(jiti@2.6.1)): + eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@2.6.1)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -24123,7 +24311,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.39.0(jiti@2.6.1) + eslint: 9.39.1(jiti@2.6.1) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -24153,15 +24341,15 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.39.0(jiti@2.6.1): + eslint@9.39.1(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.39.0 + '@eslint/js': 9.39.1 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 @@ -27378,7 +27566,7 @@ snapshots: needle@3.3.1: dependencies: iconv-lite: 0.6.3 - sax: 1.4.1 + sax: 1.4.3 optional: true negotiator@0.6.3: {} @@ -27403,7 +27591,7 @@ snapshots: node-api-version@0.2.1: dependencies: - semver: 7.7.2 + semver: 7.7.3 node-domexception@1.0.0: {} @@ -27441,7 +27629,7 @@ snapshots: make-fetch-happen: 14.0.3 nopt: 8.1.0 proc-log: 5.0.0 - semver: 7.7.2 + semver: 7.7.3 tar: 7.4.3 tinyglobby: 0.2.15 which: 5.0.0 @@ -27733,7 +27921,7 @@ snapshots: is-inside-container: 1.0.0 wsl-utils: 0.1.0 - openai@6.7.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@4.1.12): + openai@6.8.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@4.1.12): optionalDependencies: ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) zod: 4.1.12 @@ -29110,7 +29298,7 @@ snapshots: react: 19.2.0 scheduler: 0.27.0 - react-i18next@16.2.3(i18next@25.6.0(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3): + react-i18next@16.2.4(i18next@25.6.0(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3): dependencies: '@babel/runtime': 7.28.4 html-parse-stringify: 3.0.1 @@ -29817,7 +30005,7 @@ snapshots: '@parcel/watcher': 2.5.1 optional: true - sax@1.4.1: {} + sax@1.4.3: {} saxes@5.0.1: dependencies: @@ -30813,7 +31001,7 @@ snapshots: css-what: 6.2.2 csso: 5.0.5 picocolors: 1.1.1 - sax: 1.4.1 + sax: 1.4.3 swagger-jsdoc@6.2.8(openapi-types@12.1.3): dependencies: @@ -31299,13 +31487,24 @@ snapshots: typescript: 5.9.3 yaml: 2.8.1 - typescript-eslint@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.0(jiti@2.6.1) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript-eslint@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -32147,12 +32346,12 @@ snapshots: xml2js@0.5.0: dependencies: - sax: 1.4.1 + sax: 1.4.3 xmlbuilder: 11.0.1 xml2js@0.6.2: dependencies: - sax: 1.4.1 + sax: 1.4.3 xmlbuilder: 11.0.1 xmlbuilder@11.0.1: {}