diff --git a/README.md b/README.md
index 22bb14c94..dc0e1f662 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# TriliumNext Notes
+ 
+
[English](./README.md) | [Chinese](./README-ZH_CN.md) | [Russian](./README.ru.md) | [Japanese](./README.ja.md) | [Italian](./README.it.md) | [Spanish](./README.es.md)
TriliumNext Notes is an open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases.
diff --git a/bin/deb-options.json b/bin/deb-options.json
deleted file mode 100644
index 86531cc48..000000000
--- a/bin/deb-options.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "src": "dist/trilium-linux-x64",
- "dest": "dist/",
- "compression": "xz",
- "name": "trilium",
- "productName": "Trilium Notes",
- "genericName": "Note taker",
- "description": "Trilium Notes is a hierarchical note taking application with focus on building large personal knowledge bases.",
- "sections": "misc",
- "maintainer": "zadam.apps@gmail.com",
- "homepage": "https://github.com/zadam/trilium",
- "bin": "trilium",
- "icon": "dist/trilium-linux-x64/icon.png",
- "categories": [ "Office" ]
-}
diff --git a/bin/electron-forge/desktop.ejs b/bin/electron-forge/desktop.ejs
new file mode 100644
index 000000000..f803f37b2
--- /dev/null
+++ b/bin/electron-forge/desktop.ejs
@@ -0,0 +1,12 @@
+[Desktop Entry]
+<% if (productName) { %>Name=<%= productName %>
+<% } %><% if (description) { %>Comment=<%= description %>
+<% } %><% if (genericName) { %>GenericName=<%= genericName %>
+<% } %><% if (name) { %>Exec=<%= name %> %U
+Icon=<%= name %>
+<% } %>Type=Application
+StartupNotify=true
+<% if (productName) { %>StartupWMClass=<%= productName %>
+<% } if (categories && categories.length) { %>Categories=<%= categories.join(';') %>;
+<% } %><% if (mimeType && mimeType.length) { %>MimeType=<%= mimeType.join(';') %>;
+<% } %>
\ No newline at end of file
diff --git a/forge.config.cjs b/forge.config.cjs
index 91730ed43..8d2db5da5 100644
--- a/forge.config.cjs
+++ b/forge.config.cjs
@@ -20,13 +20,20 @@ module.exports = {
afterComplete: [(buildPath, _electronVersion, platform, _arch, callback) => {
const extraResources = getExtraResourcesForPlatform();
for (const resource of extraResources) {
+ const baseName = path.basename(resource);
let sourcePath;
if (platform === 'darwin') {
- sourcePath = path.join(buildPath, `${APP_NAME}.app`, 'Contents', 'Resources', path.basename(resource));
+ sourcePath = path.join(buildPath, `${APP_NAME}.app`, 'Contents', 'Resources', baseName);
} else {
- sourcePath = path.join(buildPath, 'resources', path.basename(resource));
+ sourcePath = path.join(buildPath, 'resources', baseName);
+ }
+ let destPath;
+
+ if (baseName !== "256x256.png") {
+ destPath = path.join(buildPath, baseName);
+ } else {
+ destPath = path.join(buildPath, "icon.png");
}
- const destPath = path.join(buildPath, path.basename(resource));
// Copy files from resources folder to root
fs.move(sourcePath, destPath)
@@ -44,6 +51,7 @@ module.exports = {
config: {
options: {
icon: "./images/app-icons/png/128x128.png",
+ desktopTemplate: path.resolve("./bin/electron-forge/desktop.ejs")
}
}
},
@@ -95,6 +103,7 @@ function getExtraResourcesForPlatform() {
case 'darwin':
break;
case 'linux':
+ resources.push("images/app-icons/png/256x256.png")
for (const script of scripts) {
resources.push(`./bin/tpl/${script}.sh`)
}
diff --git a/package-lock.json b/package-lock.json
index 134ccbea1..aed9eedac 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "trilium",
- "version": "0.90.8",
+ "version": "0.90.9-beta",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "trilium",
- "version": "0.90.8",
+ "version": "0.90.9-beta",
"license": "AGPL-3.0-only",
"dependencies": {
"@braintree/sanitize-url": "7.1.0",
@@ -23,11 +23,11 @@
"cls-hooked": "4.2.2",
"codemirror": "5.65.18",
"compression": "1.7.4",
- "cookie-parser": "1.4.6",
+ "cookie-parser": "1.4.7",
"csurf": "1.11.0",
"dayjs": "1.11.13",
"dayjs-plugin-utc": "0.1.2",
- "debounce": "2.1.1",
+ "debounce": "2.2.0",
"ejs": "3.1.10",
"electron-debug": "4.0.1",
"electron-dl": "4.0.0",
@@ -35,18 +35,18 @@
"electron-window-state": "5.0.3",
"escape-html": "1.0.3",
"eslint": "9.10.0",
- "express": "4.21.0",
+ "express": "4.21.1",
"express-partial-content": "1.0.2",
- "express-rate-limit": "7.4.0",
- "express-session": "1.18.0",
- "force-graph": "1.43.5",
+ "express-rate-limit": "7.4.1",
+ "express-session": "1.18.1",
+ "force-graph": "1.45.0",
"fs-extra": "11.2.0",
"helmet": "7.1.0",
"html": "1.0.0",
"html2plaintext": "2.1.4",
"http-proxy-agent": "7.0.2",
"https-proxy-agent": "7.0.5",
- "i18next": "23.16.0",
+ "i18next": "23.16.2",
"i18next-fs-backend": "2.3.2",
"i18next-http-backend": "2.6.2",
"image-type": "4.1.0",
@@ -63,10 +63,10 @@
"katex": "0.16.11",
"knockout": "3.5.1",
"mark.js": "8.11.1",
- "marked": "14.1.2",
+ "marked": "14.1.3",
"mermaid": "11.3.0",
"mime-types": "2.1.35",
- "mind-elixir": "4.2.0",
+ "mind-elixir": "4.2.3",
"multer": "1.4.5-lts.1",
"node-abi": "3.67.0",
"normalize-strings": "1.1.1",
@@ -79,7 +79,7 @@
"request": "2.88.2",
"safe-compare": "1.1.4",
"sanitize-filename": "1.6.3",
- "sanitize-html": "2.13.0",
+ "sanitize-html": "2.13.1",
"sax": "1.4.1",
"semver": "7.6.3",
"serve-favicon": "2.5.0",
@@ -92,7 +92,7 @@
"tree-kill": "1.2.2",
"turndown": "7.2.0",
"unescape": "1.0.1",
- "vanilla-js-wheel-zoom": "9.0.2",
+ "vanilla-js-wheel-zoom": "9.0.4",
"ws": "8.18.0",
"xml2js": "0.6.2",
"yauzl": "3.1.3"
@@ -126,7 +126,7 @@
"@types/jsdom": "21.1.7",
"@types/mime-types": "2.1.4",
"@types/multer": "1.4.12",
- "@types/node": "22.5.4",
+ "@types/node": "22.7.8",
"@types/safe-compare": "1.1.2",
"@types/sanitize-html": "2.13.0",
"@types/sax": "1.2.7",
@@ -145,14 +145,14 @@
"electron-rebuild": "3.2.9",
"esm": "3.2.25",
"iconsur": "1.7.0",
- "jasmine": "5.3.1",
+ "jasmine": "5.4.0",
"jsdoc": "4.0.3",
"lorem-ipsum": "2.0.8",
"nodemon": "3.1.7",
"rcedit": "4.0.1",
"rimraf": "6.0.1",
"ts-node": "10.9.2",
- "tslib": "2.7.0",
+ "tslib": "2.8.0",
"tsx": "4.19.1",
"typescript": "5.6.3",
"webpack": "5.95.0",
@@ -3360,9 +3360,9 @@
}
},
"node_modules/@types/express-serve-static-core": {
- "version": "4.17.43",
- "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz",
- "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz",
+ "integrity": "sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw==",
"dev": true,
"dependencies": {
"@types/node": "*",
@@ -3380,6 +3380,18 @@
"@types/express": "*"
}
},
+ "node_modules/@types/express/node_modules/@types/express-serve-static-core": {
+ "version": "4.19.6",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz",
+ "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
"node_modules/@types/fs-extra": {
"version": "9.0.13",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz",
@@ -3528,9 +3540,9 @@
}
},
"node_modules/@types/node": {
- "version": "22.5.4",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz",
- "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
+ "version": "22.7.8",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.8.tgz",
+ "integrity": "sha512-a922jJy31vqR5sk+kAdIENJjHblqcZ4RmERviFsER4WJcEONqxKcjNOlk0q7OUfrF5sddT+vng070cdfMlrPLg==",
"dependencies": {
"undici-types": "~6.19.2"
}
@@ -5319,9 +5331,9 @@
]
},
"node_modules/canvas-color-tracker": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/canvas-color-tracker/-/canvas-color-tracker-1.2.1.tgz",
- "integrity": "sha512-i5clg2pEdaWqHuEM/B74NZNLkHh5+OkXbA/T4iaBiaNDagkOCXkLNrhqUfdUugsRwuaNRU20e/OygzxWRor3yg==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/canvas-color-tracker/-/canvas-color-tracker-1.3.1.tgz",
+ "integrity": "sha512-eNycxGS7oQ3IS/9QQY41f/aQjiO9Y/MtedhCgSdsbLSxC9EyUD8L3ehl/Q3Kfmvt8um79S45PBV+5Rxm5ztdSw==",
"dependencies": {
"tinycolor2": "^1.6.0"
},
@@ -5926,11 +5938,11 @@
}
},
"node_modules/cookie-parser": {
- "version": "1.4.6",
- "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz",
- "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==",
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
+ "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
"dependencies": {
- "cookie": "0.4.1",
+ "cookie": "0.7.2",
"cookie-signature": "1.0.6"
},
"engines": {
@@ -5938,9 +5950,9 @@
}
},
"node_modules/cookie-parser/node_modules/cookie": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
- "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==",
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"engines": {
"node": ">= 0.6"
}
@@ -6753,9 +6765,9 @@
"integrity": "sha512-ExERH5o3oo6jFOdkvMP3gytTCQ9Ksi5PtylclJWghr7k7m3o2U5QrwtdiJkOxLOH4ghr0EKhpqGefzGz1VvVJg=="
},
"node_modules/debounce": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.1.1.tgz",
- "integrity": "sha512-+xRWxgel9LgTC4PwKlm7TJUK6B6qsEK77NaiNvXmeQ7Y3e6OVVsBC4a9BSptS/mAYceyAz37Oa8JTTuPRft7uQ==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.2.0.tgz",
+ "integrity": "sha512-Xks6RUDLZFdz8LIdR6q0MTH44k7FikOmnh5xkSjMig6ch45afc8sjTjRQf3P6ax8dMgcQrYO/AR2RGWURrruqw==",
"engines": {
"node": ">=18"
},
@@ -8229,16 +8241,16 @@
}
},
"node_modules/express": {
- "version": "4.21.0",
- "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
- "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
+ "version": "4.21.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
+ "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.3",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
- "cookie": "0.6.0",
+ "cookie": "0.7.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
@@ -8278,9 +8290,9 @@
}
},
"node_modules/express-rate-limit": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.4.0.tgz",
- "integrity": "sha512-v1204w3cXu5gCDmAvgvzI6qjzZzoMWKnyVDk3ACgfswTQLYiGen+r8w0VnXnGMmzEN/g8fwIQ4JrFFd4ZP6ssg==",
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.4.1.tgz",
+ "integrity": "sha512-KS3efpnpIDVIXopMc65EMbWbUht7qvTCdtCR2dD/IZmi9MIkopYESwyRqLgv8Pfu589+KqDqOdzJWW7AHoACeg==",
"engines": {
"node": ">= 16"
},
@@ -8292,11 +8304,11 @@
}
},
"node_modules/express-session": {
- "version": "1.18.0",
- "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz",
- "integrity": "sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==",
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz",
+ "integrity": "sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA==",
"dependencies": {
- "cookie": "0.6.0",
+ "cookie": "0.7.2",
"cookie-signature": "1.0.7",
"debug": "2.6.9",
"depd": "~2.0.0",
@@ -8310,9 +8322,9 @@
}
},
"node_modules/express-session/node_modules/cookie": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
- "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"engines": {
"node": ">= 0.6"
}
@@ -8358,9 +8370,9 @@
]
},
"node_modules/express/node_modules/cookie": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
- "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
+ "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"engines": {
"node": ">= 0.6"
}
@@ -8835,14 +8847,14 @@
}
},
"node_modules/force-graph": {
- "version": "1.43.5",
- "resolved": "https://registry.npmjs.org/force-graph/-/force-graph-1.43.5.tgz",
- "integrity": "sha512-HveLELh9yhZXO/QOfaFS38vlwJZ/3sKu+jarfXzRmbmihSOH/BbRWnUvmg8wLFiYy6h4HlH4lkRfZRccHYmXgA==",
+ "version": "1.45.0",
+ "resolved": "https://registry.npmjs.org/force-graph/-/force-graph-1.45.0.tgz",
+ "integrity": "sha512-QM/J72Vji5D3ug+TDu8wH+qne0zEKE9Cn7m9ocH/1RtaVY0BBqZQ4Mn6MiwNRyxwl28lsUd0F54kDpINnagvOA==",
"dependencies": {
- "@tweenjs/tween.js": "18 - 23",
+ "@tweenjs/tween.js": "18 - 25",
"accessor-fn": "1",
"bezier-js": "3 - 6",
- "canvas-color-tracker": "1",
+ "canvas-color-tracker": "^1.3",
"d3-array": "1 - 3",
"d3-drag": "2 - 3",
"d3-force-3d": "2 - 3",
@@ -9715,9 +9727,9 @@
}
},
"node_modules/i18next": {
- "version": "23.16.0",
- "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.0.tgz",
- "integrity": "sha512-Ni3CG6c14teOogY19YNRl+kYaE/Rb59khy0VyHVn4uOZ97E2E/Yziyi6r3C3s9+wacjdLZiq/LLYyx+Cgd+FCw==",
+ "version": "23.16.2",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.2.tgz",
+ "integrity": "sha512-dFyxwLXxEQK32f6tITBMaRht25mZPJhQ0WbC0p3bO2mWBal9lABTMqSka5k+GLSRWLzeJBKDpH7BeIA9TZI7Jg==",
"funding": [
{
"type": "individual",
@@ -10828,22 +10840,22 @@
}
},
"node_modules/jasmine": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.3.1.tgz",
- "integrity": "sha512-3zeUCfr3d1iga3s+NgDpggCP+ex5sdbNgqNn+Tq4yw/QfnwGrWC/ZvXX1IRm5deSIZ1LnvoeGY55F/ztbVOXPQ==",
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.4.0.tgz",
+ "integrity": "sha512-E2u4ylX5tgGYvbynImU6EUBKKrSVB1L72FEPjGh4M55ov1VsxR26RA2JU91L9YSPFgcjo4mCLyKn/QXvEYGBkA==",
"dev": true,
"dependencies": {
"glob": "^10.2.2",
- "jasmine-core": "~5.3.0"
+ "jasmine-core": "~5.4.0"
},
"bin": {
"jasmine": "bin/jasmine.js"
}
},
"node_modules/jasmine-core": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.3.0.tgz",
- "integrity": "sha512-zsOmeBKESky4toybvWEikRiZ0jHoBEu79wNArLfMdSnlLMZx3Xcp6CSm2sUcYyoJC+Uyj8LBJap/MUbVSfJ27g==",
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.4.0.tgz",
+ "integrity": "sha512-T4fio3W++llLd7LGSGsioriDHgWyhoL6YTu4k37uwJLF7DzOzspz7mNxRoM3cQdLWtL/ebazQpIf/yZGJx/gzg==",
"dev": true
},
"node_modules/jasmine/node_modules/brace-expansion": {
@@ -11817,9 +11829,9 @@
}
},
"node_modules/marked": {
- "version": "14.1.2",
- "resolved": "https://registry.npmjs.org/marked/-/marked-14.1.2.tgz",
- "integrity": "sha512-f3r0yqpz31VXiDB/wj9GaOB0a2PRLQl6vJmXiFrniNwjkKdvakqJRULhjFKJpxOchlCRiG5fcacoUZY5Xa6PEQ==",
+ "version": "14.1.3",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-14.1.3.tgz",
+ "integrity": "sha512-ZibJqTULGlt9g5k4VMARAktMAjXoVnnr+Y3aCqW1oDftcV4BA3UmrBifzXoZyenHRk75csiPu9iwsTj4VNBT0g==",
"bin": {
"marked": "bin/marked.js"
},
@@ -12028,9 +12040,9 @@
}
},
"node_modules/mind-elixir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/mind-elixir/-/mind-elixir-4.2.0.tgz",
- "integrity": "sha512-FBmTri+lfuScRtaBQGh6WNFU1Bbqp2IDq6dF9coxv5aj34wuTsacR8fwyTaK79Wh8A5mUL/D/HO/KvSMBKJBqg=="
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/mind-elixir/-/mind-elixir-4.2.3.tgz",
+ "integrity": "sha512-o/t9/mrJkRu0PE5UjXBv8ZZuhwSdm6C1Hw65v/+bIlB2CS2MOGZ/GNPvU3U4kPDu6LnCZ0kw0L7hoVfHhrZLtw=="
},
"node_modules/minimalistic-assert": {
"version": "1.0.1",
@@ -14321,9 +14333,9 @@
}
},
"node_modules/sanitize-html": {
- "version": "2.13.0",
- "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.13.0.tgz",
- "integrity": "sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==",
+ "version": "2.13.1",
+ "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.13.1.tgz",
+ "integrity": "sha512-ZXtKq89oue4RP7abL9wp/9URJcqQNABB5GGJ2acW1sdO8JTVl92f4ygD7Yc9Ze09VAZhnt2zegeU0tbNsdcLYg==",
"dependencies": {
"deepmerge": "^4.2.2",
"escape-string-regexp": "^4.0.0",
@@ -15647,9 +15659,9 @@
}
},
"node_modules/tslib": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
- "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA=="
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
+ "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA=="
},
"node_modules/tsscmp": {
"version": "1.0.6",
@@ -16032,10 +16044,9 @@
"integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
},
"node_modules/vanilla-js-wheel-zoom": {
- "version": "9.0.2",
- "resolved": "https://registry.npmjs.org/vanilla-js-wheel-zoom/-/vanilla-js-wheel-zoom-9.0.2.tgz",
- "integrity": "sha512-GleJm/qTDcfQC7gdFH4BT5vCZmnz2LOTgLAQ5CCCwftFC/zrBURRWr5Y7jRPi3W3rRf8bTIAN3hLZYFqvK5jwA==",
- "license": "MIT"
+ "version": "9.0.4",
+ "resolved": "https://registry.npmjs.org/vanilla-js-wheel-zoom/-/vanilla-js-wheel-zoom-9.0.4.tgz",
+ "integrity": "sha512-OjmS9ihEKBCRw2OQ7IiIdQGXdC5gTEEmtcAWZcPeNAJaYiS61KCd02Z72YMtIoXLGN5TZP+wliBMylLAsr6wow=="
},
"node_modules/vary": {
"version": "1.1.2",
diff --git a/package.json b/package.json
index b8c4a4132..c0f1e7bdf 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "trilium",
"productName": "TriliumNext Notes",
"description": "Build your personal knowledge base with TriliumNext Notes",
- "version": "0.90.8",
+ "version": "0.90.9-beta",
"license": "AGPL-3.0-only",
"main": "./dist/electron-main.js",
"author": {
@@ -63,11 +63,11 @@
"cls-hooked": "4.2.2",
"codemirror": "5.65.18",
"compression": "1.7.4",
- "cookie-parser": "1.4.6",
+ "cookie-parser": "1.4.7",
"csurf": "1.11.0",
"dayjs": "1.11.13",
"dayjs-plugin-utc": "0.1.2",
- "debounce": "2.1.1",
+ "debounce": "2.2.0",
"ejs": "3.1.10",
"electron-debug": "4.0.1",
"electron-dl": "4.0.0",
@@ -75,18 +75,18 @@
"electron-window-state": "5.0.3",
"escape-html": "1.0.3",
"eslint": "9.10.0",
- "express": "4.21.0",
+ "express": "4.21.1",
"express-partial-content": "1.0.2",
- "express-rate-limit": "7.4.0",
- "express-session": "1.18.0",
- "force-graph": "1.43.5",
+ "express-rate-limit": "7.4.1",
+ "express-session": "1.18.1",
+ "force-graph": "1.45.0",
"fs-extra": "11.2.0",
"helmet": "7.1.0",
"html": "1.0.0",
"html2plaintext": "2.1.4",
"http-proxy-agent": "7.0.2",
"https-proxy-agent": "7.0.5",
- "i18next": "23.16.0",
+ "i18next": "23.16.2",
"i18next-fs-backend": "2.3.2",
"i18next-http-backend": "2.6.2",
"image-type": "4.1.0",
@@ -103,10 +103,10 @@
"katex": "0.16.11",
"knockout": "3.5.1",
"mark.js": "8.11.1",
- "marked": "14.1.2",
+ "marked": "14.1.3",
"mermaid": "11.3.0",
"mime-types": "2.1.35",
- "mind-elixir": "4.2.0",
+ "mind-elixir": "4.2.3",
"multer": "1.4.5-lts.1",
"node-abi": "3.67.0",
"normalize-strings": "1.1.1",
@@ -119,7 +119,7 @@
"request": "2.88.2",
"safe-compare": "1.1.4",
"sanitize-filename": "1.6.3",
- "sanitize-html": "2.13.0",
+ "sanitize-html": "2.13.1",
"sax": "1.4.1",
"semver": "7.6.3",
"serve-favicon": "2.5.0",
@@ -132,7 +132,7 @@
"tree-kill": "1.2.2",
"turndown": "7.2.0",
"unescape": "1.0.1",
- "vanilla-js-wheel-zoom": "9.0.2",
+ "vanilla-js-wheel-zoom": "9.0.4",
"ws": "8.18.0",
"xml2js": "0.6.2",
"yauzl": "3.1.3"
@@ -163,7 +163,7 @@
"@types/jsdom": "21.1.7",
"@types/mime-types": "2.1.4",
"@types/multer": "1.4.12",
- "@types/node": "22.5.4",
+ "@types/node": "22.7.8",
"@types/safe-compare": "1.1.2",
"@types/sanitize-html": "2.13.0",
"@types/sax": "1.2.7",
@@ -182,14 +182,14 @@
"electron-rebuild": "3.2.9",
"esm": "3.2.25",
"iconsur": "1.7.0",
- "jasmine": "5.3.1",
+ "jasmine": "5.4.0",
"jsdoc": "4.0.3",
"lorem-ipsum": "2.0.8",
"nodemon": "3.1.7",
"rcedit": "4.0.1",
"rimraf": "6.0.1",
"ts-node": "10.9.2",
- "tslib": "2.7.0",
+ "tslib": "2.8.0",
"tsx": "4.19.1",
"typescript": "5.6.3",
"webpack": "5.95.0",
diff --git a/src/public/app/components/entrypoints.js b/src/public/app/components/entrypoints.js
index 6a375d5af..6ee06ff65 100644
--- a/src/public/app/components/entrypoints.js
+++ b/src/public/app/components/entrypoints.js
@@ -9,6 +9,7 @@ import ws from "../services/ws.js";
import bundleService from "../services/bundle.js";
import froca from "../services/froca.js";
import linkService from "../services/link.js";
+import { t } from "../services/i18n.js";
export default class Entrypoints extends Component {
constructor() {
@@ -172,13 +173,13 @@ export default class Entrypoints extends Component {
const resp = await server.post(`sql/execute/${note.noteId}`);
if (!resp.success) {
- toastService.showError(`Error occurred while executing SQL query: ${resp.error}`);
+ toastService.showError(t("entrypoints.sql-error", { message: resp.error }));
}
await appContext.triggerEvent('sqlQueryResults', {ntxId: ntxId, results: resp.results});
}
- toastService.showMessage("Note executed");
+ toastService.showMessage(t("entrypoints.note-executed"));
}
hideAllPopups() {
@@ -200,6 +201,6 @@ export default class Entrypoints extends Component {
await server.post(`notes/${noteId}/revision`);
- toastService.showMessage("Note revision has been created.");
+ toastService.showMessage(t("entrypoints.note-revision-created"));
}
}
diff --git a/src/public/app/components/tab_manager.js b/src/public/app/components/tab_manager.js
index 861a54502..235aa5cd1 100644
--- a/src/public/app/components/tab_manager.js
+++ b/src/public/app/components/tab_manager.js
@@ -551,7 +551,7 @@ export default class TabManager extends Component {
await this.removeNoteContext(ntxIdToRemove);
}
}
-
+
async closeOtherTabsCommand({ntxId}) {
for (const ntxIdToRemove of this.mainNoteContexts.map(nc => nc.ntxId)) {
if (ntxIdToRemove !== ntxId) {
@@ -560,6 +560,18 @@ export default class TabManager extends Component {
}
}
+ async closeRightTabsCommand({ntxId}) {
+ const ntxIds = this.mainNoteContexts.map(nc => nc.ntxId);
+ const index = ntxIds.indexOf(ntxId);
+
+ if (index !== -1) {
+ const idsToRemove = ntxIds.slice(index + 1);
+ for (const ntxIdToRemove of idsToRemove) {
+ await this.removeNoteContext(ntxIdToRemove);
+ }
+ }
+ }
+
async closeTabCommand({ntxId}) {
await this.removeNoteContext(ntxId);
}
diff --git a/src/public/app/desktop.js b/src/public/app/desktop.js
index febb9a8f9..835624d35 100644
--- a/src/public/app/desktop.js
+++ b/src/public/app/desktop.js
@@ -9,9 +9,9 @@ import electronContextMenu from "./menus/electron_context_menu.js";
import glob from "./services/glob.js";
import { t } from "./services/i18n.js";
+await appContext.earlyInit();
+
bundleService.getWidgetBundlesByParent().then(async widgetBundles => {
- await appContext.earlyInit();
-
// A dynamic import is required for layouts since they initialize components which require translations.
const DesktopLayout = (await import("./layouts/desktop_layout.js")).default;
diff --git a/src/public/app/menus/launcher_context_menu.js b/src/public/app/menus/launcher_context_menu.js
index 5f6607f89..b7c722dae 100644
--- a/src/public/app/menus/launcher_context_menu.js
+++ b/src/public/app/menus/launcher_context_menu.js
@@ -3,6 +3,7 @@ import froca from "../services/froca.js";
import contextMenu from "./context_menu.js";
import dialogService from "../services/dialog.js";
import server from "../services/server.js";
+import { t } from '../services/i18n.js';
export default class LauncherContextMenu {
/**
@@ -33,29 +34,27 @@ export default class LauncherContextMenu {
const isAvailableItem = parentNoteId === '_lbAvailableLaunchers';
const isItem = isVisibleItem || isAvailableItem;
const canBeDeleted = !note.noteId.startsWith("_"); // fixed notes can't be deleted
- const canBeReset = !canBeDeleted && note.isLaunchBarConfig();;
+ const canBeReset = !canBeDeleted && note.isLaunchBarConfig();
return [
- (isVisibleRoot || isAvailableRoot) ? { title: 'Add a note launcher', command: 'addNoteLauncher', uiIcon: "bx bx-plus" } : null,
- (isVisibleRoot || isAvailableRoot) ? { title: 'Add a script launcher', command: 'addScriptLauncher', uiIcon: "bx bx-plus" } : null,
- (isVisibleRoot || isAvailableRoot) ? { title: 'Add a custom widget', command: 'addWidgetLauncher', uiIcon: "bx bx-plus" } : null,
- (isVisibleRoot || isAvailableRoot) ? { title: 'Add spacer', command: 'addSpacerLauncher', uiIcon: "bx bx-plus" } : null,
+ (isVisibleRoot || isAvailableRoot) ? { title: t("launcher_context_menu.add-note-launcher"), command: 'addNoteLauncher', uiIcon: "bx bx-plus" } : null,
+ (isVisibleRoot || isAvailableRoot) ? { title: t("launcher_context_menu.add-script-launcher"), command: 'addScriptLauncher', uiIcon: "bx bx-plus" } : null,
+ (isVisibleRoot || isAvailableRoot) ? { title: t("launcher_context_menu.add-custom-widget"), command: 'addWidgetLauncher', uiIcon: "bx bx-plus" } : null,
+ (isVisibleRoot || isAvailableRoot) ? { title: t("launcher_context_menu.add-spacer"), command: 'addSpacerLauncher', uiIcon: "bx bx-plus" } : null,
(isVisibleRoot || isAvailableRoot) ? { title: "----" } : null,
- { title: 'Delete ', command: "deleteNotes", uiIcon: "bx bx-trash", enabled: canBeDeleted },
- { title: 'Reset', command: "resetLauncher", uiIcon: "bx bx-empty", enabled: canBeReset},
+ { title: `${t("launcher_context_menu.delete")} `, command: "deleteNotes", uiIcon: "bx bx-trash", enabled: canBeDeleted },
+ { title: t("launcher_context_menu.reset"), command: "resetLauncher", uiIcon: "bx bx-empty", enabled: canBeReset},
{ title: "----" },
- isAvailableItem ? { title: 'Move to visible launchers', command: "moveLauncherToVisible", uiIcon: "bx bx-show", enabled: true } : null,
- isVisibleItem ? { title: 'Move to available launchers', command: "moveLauncherToAvailable", uiIcon: "bx bx-hide", enabled: true } : null,
- { title: `Duplicate launcher `, command: "duplicateSubtree", uiIcon: "bx bx-empty",
+ isAvailableItem ? { title: t("launcher_context_menu.move-to-visible-launchers"), command: "moveLauncherToVisible", uiIcon: "bx bx-show", enabled: true } : null,
+ isVisibleItem ? { title: t("launcher_context_menu.move-to-available-launchers"), command: "moveLauncherToAvailable", uiIcon: "bx bx-hide", enabled: true } : null,
+ { title: `${t("launcher_context_menu.duplicate-launcher")} `, command: "duplicateSubtree", uiIcon: "bx bx-empty",
enabled: isItem }
].filter(row => row !== null);
}
async selectMenuItemHandler({command}) {
if (command === 'resetLauncher') {
- const confirmed = await dialogService.confirm(`Do you really want to reset "${this.node.title}"?
- All data / settings in this note (and its children) will be lost
- and the launcher will be returned to its original location.`);
+ const confirmed = await dialogService.confirm(t("launcher_context_menu.reset_launcher_confirm", { title: this.node.title }));
if (confirmed) {
await server.post(`special-notes/launchers/${this.node.data.noteId}/reset`);
diff --git a/src/public/app/menus/tree_context_menu.js b/src/public/app/menus/tree_context_menu.js
index caa572816..7609c99f5 100644
--- a/src/public/app/menus/tree_context_menu.js
+++ b/src/public/app/menus/tree_context_menu.js
@@ -136,7 +136,7 @@ export default class TreeContextMenu {
this.treeWidget.triggerCommand("openNewNoteSplit", {ntxId, notePath});
}
else if (command === 'convertNoteToAttachment') {
- if (!await dialogService.confirm(`Are you sure you want to convert note selected notes into attachments of their parent notes?`)) {
+ if (!await dialogService.confirm(t("tree-context-menu.convert-to-attachment-confirm"))) {
return;
}
@@ -154,7 +154,7 @@ export default class TreeContextMenu {
}
}
- toastService.showMessage(`${converted} notes have been converted to attachments.`);
+ toastService.showMessage(t("tree-context-menu.converted-to-attachments", { count: converted }));
}
else if (command === 'copyNotePathToClipboard') {
navigator.clipboard.writeText('#' + notePath);
diff --git a/src/public/app/services/branches.js b/src/public/app/services/branches.js
index 64281d361..803c59147 100644
--- a/src/public/app/services/branches.js
+++ b/src/public/app/services/branches.js
@@ -5,6 +5,7 @@ import froca from "./froca.js";
import hoistedNoteService from "./hoisted_note.js";
import ws from "./ws.js";
import appContext from "../components/app_context.js";
+import { t } from './i18n.js';
async function moveBeforeBranch(branchIdsToMove, beforeBranchId) {
branchIdsToMove = filterRootNote(branchIdsToMove);
@@ -13,7 +14,7 @@ async function moveBeforeBranch(branchIdsToMove, beforeBranchId) {
const beforeBranch = froca.getBranch(beforeBranchId);
if (['root', '_lbRoot', '_lbAvailableLaunchers', '_lbVisibleLaunchers'].includes(beforeBranch.noteId)) {
- toastService.showError('Cannot move notes here.');
+ toastService.showError(t("branches.cannot-move-notes-here"));
return;
}
@@ -42,7 +43,7 @@ async function moveAfterBranch(branchIdsToMove, afterBranchId) {
];
if (forbiddenNoteIds.includes(afterNote.noteId)) {
- toastService.showError('Cannot move notes here.');
+ toastService.showError(t("branches.cannot-move-notes-here"));
return;
}
@@ -62,7 +63,7 @@ async function moveToParentNote(branchIdsToMove, newParentBranchId) {
const newParentBranch = froca.getBranch(newParentBranchId);
if (newParentBranch.noteId === '_lbRoot') {
- toastService.showError('Cannot move notes here.');
+ toastService.showError(t("branches.cannot-move-notes-here"));
return;
}
@@ -192,7 +193,7 @@ function filterRootNote(branchIds) {
function makeToast(id, message) {
return {
id: id,
- title: "Delete status",
+ title: t("branches.delete-status"),
message: message,
icon: "trash"
};
@@ -207,9 +208,9 @@ ws.subscribeToMessages(async message => {
toastService.closePersistent(message.taskId);
toastService.showError(message.message);
} else if (message.type === 'taskProgressCount') {
- toastService.showPersistent(makeToast(message.taskId, `Delete notes in progress: ${message.progressCount}`));
+ toastService.showPersistent(makeToast(message.taskId, t("branches.delete-notes-in-progress", { count: message.progressCount })));
} else if (message.type === 'taskSucceeded') {
- const toast = makeToast(message.taskId, "Delete finished successfully.");
+ const toast = makeToast(message.taskId, t("branches.delete-finished-successfully"));
toast.closeAfter = 5000;
toastService.showPersistent(toast);
@@ -225,9 +226,9 @@ ws.subscribeToMessages(async message => {
toastService.closePersistent(message.taskId);
toastService.showError(message.message);
} else if (message.type === 'taskProgressCount') {
- toastService.showPersistent(makeToast(message.taskId, `Undeleting notes in progress: ${message.progressCount}`));
+ toastService.showPersistent(makeToast(message.taskId, t("branches.undeleting-notes-in-progress", { count: message.progressCount })));
} else if (message.type === 'taskSucceeded') {
- const toast = makeToast(message.taskId, "Undeleting notes finished successfully.");
+ const toast = makeToast(message.taskId, t("branches.undeleting-notes-finished-successfully"));
toast.closeAfter = 5000;
toastService.showPersistent(toast);
diff --git a/src/public/app/services/bundle.js b/src/public/app/services/bundle.js
index 51348111a..e0a81eee4 100644
--- a/src/public/app/services/bundle.js
+++ b/src/public/app/services/bundle.js
@@ -3,6 +3,7 @@ import server from "./server.js";
import toastService from "./toast.js";
import froca from "./froca.js";
import utils from "./utils.js";
+import { t } from "./i18n.js";
async function getAndExecuteBundle(noteId, originEntity = null, script = null, params = null) {
const bundle = await server.post(`script/bundle/${noteId}`, {
@@ -75,9 +76,23 @@ async function getWidgetBundlesByParent() {
try {
widget = await executeBundle(bundle);
- widgetsByParent.add(widget);
- }
- catch (e) {
+ if (widget) {
+ widget._noteId = bundle.noteId;
+ widgetsByParent.add(widget);
+ }
+ } catch (e) {
+ const noteId = bundle.noteId;
+ const note = await froca.getNote(noteId);
+ toastService.showPersistent({
+ title: t("toast.bundle-error.title"),
+ icon: "alert",
+ message: t("toast.bundle-error.message", {
+ id: noteId,
+ title: note.title,
+ message: e.message
+ })
+ });
+
logError("Widget initialization failed: ", e);
continue;
}
diff --git a/src/public/app/services/clipboard.js b/src/public/app/services/clipboard.js
index 424784285..4db356816 100644
--- a/src/public/app/services/clipboard.js
+++ b/src/public/app/services/clipboard.js
@@ -78,7 +78,7 @@ async function copy(branchIds) {
clipboard.writeHTML(links.join(', '));
}
- toastService.showMessage("Note(s) have been copied into clipboard.");
+ toastService.showMessage(t("clipboard.copied"));
}
function cut(branchIds) {
@@ -87,7 +87,7 @@ function cut(branchIds) {
if (clipboardBranchIds.length > 0) {
clipboardMode = 'cut';
- toastService.showMessage("Note(s) have been cut into clipboard.");
+ toastService.showMessage(t("clipboard.cut"));
}
}
diff --git a/src/public/app/services/frontend_script_api.js b/src/public/app/services/frontend_script_api.js
index 1cc79e10f..5af37876a 100644
--- a/src/public/app/services/frontend_script_api.js
+++ b/src/public/app/services/frontend_script_api.js
@@ -217,8 +217,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
*/
this.runOnBackend = async (func, params = []) => {
if (func?.constructor.name === "AsyncFunction" || func?.startsWith?.("async ")) {
- toastService.showError("You're passing an async function to api.runOnBackend() which will likely not work as you intended. "
- + "Either make the function synchronous (by removing 'async' keyword), or use api.runAsyncOnBackendWithManualTransactionHandling()");
+ toastService.showError(t("frontend_script_api.async_warning"));
}
return await this.__runOnBackendInner(func, params, true);
@@ -240,8 +239,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
*/
this.runAsyncOnBackendWithManualTransactionHandling = async (func, params = []) => {
if (func?.constructor.name === "Function" || func?.startsWith?.("function")) {
- toastService.showError("You're passing a synchronous function to api.runAsyncOnBackendWithManualTransactionHandling(), " +
- "while you should likely use api.runOnBackend() instead.");
+ toastService.showError(t("frontend_script_api.sync_warning"));
}
return await this.__runOnBackendInner(func, params, false);
diff --git a/src/public/app/services/glob.js b/src/public/app/services/glob.js
index 7177a6f95..f523a677e 100644
--- a/src/public/app/services/glob.js
+++ b/src/public/app/services/glob.js
@@ -26,21 +26,6 @@ function setupGlobs() {
// for CKEditor integration (button on block toolbar)
window.glob.importMarkdownInline = async () => appContext.triggerCommand("importMarkdownInline");
- window.glob.SEARCH_HELP_TEXT = `
- Search tips - also see
-
-
-
- #abc
- returns notes with label abc#year = 2019
- matches notes with label year
having value 2019
#rock #pop
- matches notes which have both rock
and pop
labels#rock or #pop
- only one of the labels must be present#year <= 2000
- numerical comparison (also >, >=, <).note.dateCreated >= MONTH-1
- notes created in the last month=handler
- will execute script defined in handler
relation to get results