diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml
index 40423c776..5e8fb1301 100644
--- a/.github/workflows/deploy-docs.yml
+++ b/.github/workflows/deploy-docs.yml
@@ -10,6 +10,7 @@ on:
paths:
- 'docs/**'
- 'apps/edit-docs/**'
+ - 'apps/build-docs/**'
- 'packages/share-theme/**'
# Allow manual triggering from Actions tab
@@ -23,6 +24,7 @@ on:
paths:
- 'docs/**'
- 'apps/edit-docs/**'
+ - 'apps/build-docs/**'
- 'packages/share-theme/**'
jobs:
@@ -60,6 +62,8 @@ jobs:
- name: Validate Built Site
run: |
test -f site/index.html || (echo "ERROR: site/index.html not found" && exit 1)
+ test -f site/developer-guide/index.html || (echo "ERROR: site/developer-guide/index.html not found" && exit 1)
+ echo "✓ User Guide and Developer Guide built successfully"
- name: Deploy
uses: ./.github/actions/deploy-to-cloudflare-pages
diff --git a/.nvmrc b/.nvmrc
index f5b3ef39f..40115e966 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-22.21.0
\ No newline at end of file
+24.11.0
\ No newline at end of file
diff --git a/_regroup/package.json b/_regroup/package.json
index a3eb68e35..9f15f392a 100644
--- a/_regroup/package.json
+++ b/_regroup/package.json
@@ -38,19 +38,17 @@
"@playwright/test": "1.56.1",
"@stylistic/eslint-plugin": "5.5.0",
"@types/express": "5.0.5",
- "@types/node": "24.9.1",
+ "@types/node": "24.10.0",
"@types/yargs": "17.0.34",
"@vitest/coverage-v8": "4.0.6",
- "eslint": "9.38.0",
+ "eslint": "9.39.1",
"eslint-plugin-simple-import-sort": "12.1.1",
"esm": "3.2.25",
"jsdoc": "4.0.5",
"lorem-ipsum": "2.0.8",
"rcedit": "4.0.1",
- "rimraf": "6.0.1",
- "tslib": "2.8.1",
- "typedoc": "0.28.14",
- "typedoc-plugin-missing-exports": "4.1.2"
+ "rimraf": "6.1.0",
+ "tslib": "2.8.1"
},
"optionalDependencies": {
"appdmg": "0.6.6"
diff --git a/_regroup/typedoc.json b/_regroup/typedoc.json
deleted file mode 100644
index 30771621c..000000000
--- a/_regroup/typedoc.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "entryPoints": [
- "src/services/backend_script_entrypoint.ts",
- "src/public/app/services/frontend_script_entrypoint.ts"
- ],
- "plugin": [
- "typedoc-plugin-missing-exports"
- ],
- "outputs": [
- {
- "name": "html",
- "path": "./docs/Script API"
- }
- ]
-}
diff --git a/apps/build-docs/package.json b/apps/build-docs/package.json
new file mode 100644
index 000000000..00196de82
--- /dev/null
+++ b/apps/build-docs/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "build-docs",
+ "version": "1.0.0",
+ "description": "",
+ "main": "src/main.ts",
+ "scripts": {
+ "start": "tsx ."
+ },
+ "keywords": [],
+ "author": "Elian Doran ",
+ "license": "AGPL-3.0-only",
+ "packageManager": "pnpm@10.20.0",
+ "devDependencies": {
+ "@redocly/cli": "2.11.0",
+ "archiver": "7.0.1",
+ "fs-extra": "11.3.2",
+ "react": "19.2.0",
+ "react-dom": "19.2.0",
+ "typedoc": "0.28.14",
+ "typedoc-plugin-missing-exports": "4.1.2"
+ }
+}
diff --git a/apps/build-docs/src/backend_script_entrypoint.ts b/apps/build-docs/src/backend_script_entrypoint.ts
new file mode 100644
index 000000000..bc9087c0c
--- /dev/null
+++ b/apps/build-docs/src/backend_script_entrypoint.ts
@@ -0,0 +1,36 @@
+/**
+ * The backend script API is accessible to code notes with the "JS (backend)" language.
+ *
+ * The entire API is exposed as a single global: {@link api}
+ *
+ * @module Backend Script API
+ */
+
+/**
+ * This file creates the entrypoint for TypeDoc that simulates the context from within a
+ * script note on the server side.
+ *
+ * Make sure to keep in line with backend's `script_context.ts`.
+ */
+
+export type { default as AbstractBeccaEntity } from "../../server/src/becca/entities/abstract_becca_entity.js";
+export type { default as BAttachment } from "../../server/src/becca/entities/battachment.js";
+export type { default as BAttribute } from "../../server/src/becca/entities/battribute.js";
+export type { default as BBranch } from "../../server/src/becca/entities/bbranch.js";
+export type { default as BEtapiToken } from "../../server/src/becca/entities/betapi_token.js";
+export type { BNote };
+export type { default as BOption } from "../../server/src/becca/entities/boption.js";
+export type { default as BRecentNote } from "../../server/src/becca/entities/brecent_note.js";
+export type { default as BRevision } from "../../server/src/becca/entities/brevision.js";
+
+import BNote from "../../server/src/becca/entities/bnote.js";
+import BackendScriptApi, { type Api } from "../../server/src/services/backend_script_api.js";
+
+export type { Api };
+
+const fakeNote = new BNote();
+
+/**
+ * The `api` global variable allows access to the backend script API, which is documented in {@link Api}.
+ */
+export const api: Api = new BackendScriptApi(fakeNote, {});
diff --git a/apps/edit-docs/src/build-docs.ts b/apps/build-docs/src/build-docs.ts
similarity index 57%
rename from apps/edit-docs/src/build-docs.ts
rename to apps/build-docs/src/build-docs.ts
index aca569772..5d1a0cdd6 100644
--- a/apps/edit-docs/src/build-docs.ts
+++ b/apps/build-docs/src/build-docs.ts
@@ -4,24 +4,22 @@ process.env.NODE_ENV = "development";
import cls from "@triliumnext/server/src/services/cls.js";
import { dirname, join, resolve } from "path";
-import fs, { copyFile } from "fs/promises";
-import fsExtra, { createWriteStream, type WriteStream } from "fs-extra";
+import * as fs from "fs/promises";
+import * as fsExtra from "fs-extra";
import archiver from "archiver";
+import { WriteStream } from "fs";
+import { execSync } from "child_process";
+import BuildContext from "./context.js";
const DOCS_ROOT = "../../../docs";
const OUTPUT_DIR = "../../site";
-async function main() {
- const i18n = await import("@triliumnext/server/src/services/i18n.js");
- await i18n.initializeTranslations();
+async function importAndExportDocs(sourcePath: string, outputSubDir: string) {
+ const note = await importData(sourcePath);
- const sqlInit = (await import("../../server/src/services/sql_init.js")).default;
- await sqlInit.createInitialDatabase(true);
-
- const note = await importData(join(__dirname, DOCS_ROOT, "User Guide"));
-
- // Export
- const zipFilePath = "output.zip";
+ // Use a meaningful name for the temporary zip file
+ const zipName = outputSubDir || "user-guide";
+ const zipFilePath = `output-${zipName}.zip`;
try {
const { exportToZip } = (await import("@triliumnext/server/src/services/export/zip.js")).default;
const branch = note.getParentBranches()[0];
@@ -30,28 +28,53 @@ async function main() {
"export",
null
);
- const fileOutputStream = createWriteStream(zipFilePath);
+ const fileOutputStream = fsExtra.createWriteStream(zipFilePath);
await exportToZip(taskContext, branch, "share", fileOutputStream);
await waitForStreamToFinish(fileOutputStream);
- await extractZip(zipFilePath, OUTPUT_DIR);
+
+ // Output to root directory if outputSubDir is empty, otherwise to subdirectory
+ const outputPath = outputSubDir ? join(OUTPUT_DIR, outputSubDir) : OUTPUT_DIR;
+ await extractZip(zipFilePath, outputPath);
} finally {
if (await fsExtra.exists(zipFilePath)) {
await fsExtra.rm(zipFilePath);
}
}
+}
+
+async function buildDocsInner() {
+ const i18n = await import("@triliumnext/server/src/services/i18n.js");
+ await i18n.initializeTranslations();
+
+ const sqlInit = (await import("../../server/src/services/sql_init.js")).default;
+ await sqlInit.createInitialDatabase(true);
+
+ // Wait for becca to be loaded before importing data
+ const beccaLoader = await import("../../server/src/becca/becca_loader.js");
+ await beccaLoader.beccaLoaded;
+
+ // Build User Guide
+ console.log("Building User Guide...");
+ await importAndExportDocs(join(__dirname, DOCS_ROOT, "User Guide"), "user-guide");
+
+ // Build Developer Guide
+ console.log("Building Developer Guide...");
+ await importAndExportDocs(join(__dirname, DOCS_ROOT, "Developer Guide"), "developer-guide");
// Copy favicon.
- await copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "favicon.ico"));
+ await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "favicon.ico"));
+ await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "user-guide", "favicon.ico"));
+ await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "developer-guide", "favicon.ico"));
console.log("Documentation built successfully!");
}
export async function importData(path: string) {
const buffer = await createImportZip(path);
- const importService = (await import("@triliumnext/server/src/services/import/zip.js")).default;
- const TaskContext = (await import("@triliumnext/server/src/services/task_context.js")).default;
+ const importService = (await import("../../server/src/services/import/zip.js")).default;
+ const TaskContext = (await import("../../server/src/services/task_context.js")).default;
const context = new TaskContext("no-progress-reporting", "importNotes", null);
- const becca = (await import("@triliumnext/server/src/becca/becca.js")).default;
+ const becca = (await import("../../server/src/becca/becca.js")).default;
const rootNote = becca.getRoot();
if (!rootNote) {
@@ -106,4 +129,19 @@ export async function extractZip(zipFilePath: string, outputPath: string, ignore
});
}
-cls.init(main);
+export default async function buildDocs({ gitRootDir }: BuildContext) {
+ // Build the share theme.
+ execSync(`pnpm run --filter share-theme build`, {
+ stdio: "inherit",
+ cwd: gitRootDir
+ });
+
+ // Trigger the actual build.
+ await new Promise((res, rej) => {
+ cls.init(() => {
+ buildDocsInner()
+ .catch(rej)
+ .then(res);
+ });
+ });
+}
diff --git a/apps/build-docs/src/context.ts b/apps/build-docs/src/context.ts
new file mode 100644
index 000000000..ab2289e50
--- /dev/null
+++ b/apps/build-docs/src/context.ts
@@ -0,0 +1,4 @@
+export default interface BuildContext {
+ gitRootDir: string;
+ baseDir: string;
+}
diff --git a/apps/build-docs/src/frontend_script_entrypoint.ts b/apps/build-docs/src/frontend_script_entrypoint.ts
new file mode 100644
index 000000000..768774eca
--- /dev/null
+++ b/apps/build-docs/src/frontend_script_entrypoint.ts
@@ -0,0 +1,28 @@
+/**
+ * The front script API is accessible to code notes with the "JS (frontend)" language.
+ *
+ * The entire API is exposed as a single global: {@link api}
+ *
+ * @module Frontend Script API
+ */
+
+/**
+ * This file creates the entrypoint for TypeDoc that simulates the context from within a
+ * script note.
+ *
+ * Make sure to keep in line with frontend's `script_context.ts`.
+ */
+
+export type { default as BasicWidget } from "../../client/src/widgets/basic_widget.js";
+export type { default as FAttachment } from "../../client/src/entities/fattachment.js";
+export type { default as FAttribute } from "../../client/src/entities/fattribute.js";
+export type { default as FBranch } from "../../client/src/entities/fbranch.js";
+export type { default as FNote } from "../../client/src/entities/fnote.js";
+export type { Api } from "../../client/src/services/frontend_script_api.js";
+export type { default as NoteContextAwareWidget } from "../../client/src/widgets/note_context_aware_widget.js";
+export type { default as RightPanelWidget } from "../../client/src/widgets/right_panel_widget.js";
+
+import FrontendScriptApi, { type Api } from "../../client/src/services/frontend_script_api.js";
+
+//@ts-expect-error
+export const api: Api = new FrontendScriptApi();
diff --git a/apps/build-docs/src/index.html b/apps/build-docs/src/index.html
new file mode 100644
index 000000000..47a0bfb34
--- /dev/null
+++ b/apps/build-docs/src/index.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Redirecting...
+
+
+ If you are not redirected automatically, click here .
+
+
\ No newline at end of file
diff --git a/apps/build-docs/src/main.ts b/apps/build-docs/src/main.ts
new file mode 100644
index 000000000..d94ada167
--- /dev/null
+++ b/apps/build-docs/src/main.ts
@@ -0,0 +1,30 @@
+import { join } from "path";
+import BuildContext from "./context";
+import buildSwagger from "./swagger";
+import { cpSync, existsSync, mkdirSync, rmSync } from "fs";
+import buildDocs from "./build-docs";
+import buildScriptApi from "./script-api";
+
+const context: BuildContext = {
+ gitRootDir: join(__dirname, "../../../"),
+ baseDir: join(__dirname, "../../../site")
+};
+
+async function main() {
+ // Clean input dir.
+ if (existsSync(context.baseDir)) {
+ rmSync(context.baseDir, { recursive: true });
+ }
+ mkdirSync(context.baseDir);
+
+ // Start building.
+ await buildDocs(context);
+ buildSwagger(context);
+ buildScriptApi(context);
+
+ // 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/build-docs/src/script-api.ts b/apps/build-docs/src/script-api.ts
new file mode 100644
index 000000000..8473ae3a0
--- /dev/null
+++ b/apps/build-docs/src/script-api.ts
@@ -0,0 +1,15 @@
+import { execSync } from "child_process";
+import BuildContext from "./context";
+import { join } from "path";
+
+export default function buildScriptApi({ baseDir, gitRootDir }: BuildContext) {
+ // Generate types
+ execSync(`pnpm typecheck`, { stdio: "inherit", cwd: gitRootDir });
+
+ for (const config of [ "backend", "frontend" ]) {
+ const outDir = join(baseDir, "script-api", config);
+ execSync(`pnpm typedoc --options typedoc.${config}.json --html "${outDir}"`, {
+ stdio: "inherit"
+ });
+ }
+}
diff --git a/apps/build-docs/src/swagger.ts b/apps/build-docs/src/swagger.ts
new file mode 100644
index 000000000..b3677aeeb
--- /dev/null
+++ b/apps/build-docs/src/swagger.ts
@@ -0,0 +1,32 @@
+import BuildContext from "./context";
+import { join } from "path";
+import { execSync } from "child_process";
+import { mkdirSync } from "fs";
+
+interface BuildInfo {
+ specPath: string;
+ outDir: string;
+}
+
+const DIR_PREFIX = "rest-api";
+
+const buildInfos: BuildInfo[] = [
+ {
+ // Paths are relative to Git root.
+ specPath: "apps/server/internal.openapi.yaml",
+ outDir: `${DIR_PREFIX}/internal`
+ },
+ {
+ specPath: "apps/server/etapi.openapi.yaml",
+ outDir: `${DIR_PREFIX}/etapi`
+ }
+];
+
+export default function buildSwagger({ baseDir, gitRootDir }: BuildContext) {
+ for (const { specPath, outDir } of buildInfos) {
+ const absSpecPath = join(gitRootDir, specPath);
+ const targetDir = join(baseDir, outDir);
+ mkdirSync(targetDir, { recursive: true });
+ execSync(`pnpm redocly build-docs ${absSpecPath} -o ${targetDir}/index.html`, { stdio: "inherit" });
+ }
+}
diff --git a/apps/build-docs/tsconfig.app.json b/apps/build-docs/tsconfig.app.json
new file mode 100644
index 000000000..b9e17115a
--- /dev/null
+++ b/apps/build-docs/tsconfig.app.json
@@ -0,0 +1,36 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "target": "ES2020",
+ "outDir": "dist",
+ "strict": false,
+ "types": [
+ "node",
+ "express"
+ ],
+ "rootDir": "src",
+ "tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo"
+ },
+ "include": [
+ "src/**/*.ts",
+ "../server/src/*.d.ts"
+ ],
+ "exclude": [
+ "eslint.config.js",
+ "eslint.config.cjs",
+ "eslint.config.mjs"
+ ],
+ "references": [
+ {
+ "path": "../server/tsconfig.app.json"
+ },
+ {
+ "path": "../desktop/tsconfig.app.json"
+ },
+ {
+ "path": "../client/tsconfig.app.json"
+ }
+ ]
+}
diff --git a/apps/build-docs/tsconfig.json b/apps/build-docs/tsconfig.json
new file mode 100644
index 000000000..858921cfb
--- /dev/null
+++ b/apps/build-docs/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "include": [],
+ "references": [
+ {
+ "path": "../server"
+ },
+ {
+ "path": "../client"
+ },
+ {
+ "path": "./tsconfig.app.json"
+ }
+ ]
+}
diff --git a/apps/build-docs/typedoc.backend.json b/apps/build-docs/typedoc.backend.json
new file mode 100644
index 000000000..1781774c6
--- /dev/null
+++ b/apps/build-docs/typedoc.backend.json
@@ -0,0 +1,10 @@
+{
+ "$schema": "https://typedoc.org/schema.json",
+ "name": "Trilium Backend API",
+ "entryPoints": [
+ "src/backend_script_entrypoint.ts"
+ ],
+ "plugin": [
+ "typedoc-plugin-missing-exports"
+ ]
+}
diff --git a/apps/build-docs/typedoc.frontend.json b/apps/build-docs/typedoc.frontend.json
new file mode 100644
index 000000000..f07d20dc7
--- /dev/null
+++ b/apps/build-docs/typedoc.frontend.json
@@ -0,0 +1,10 @@
+{
+ "$schema": "https://typedoc.org/schema.json",
+ "name": "Trilium Frontend API",
+ "entryPoints": [
+ "src/frontend_script_entrypoint.ts"
+ ],
+ "plugin": [
+ "typedoc-plugin-missing-exports"
+ ]
+}
diff --git a/apps/client/package.json b/apps/client/package.json
index 6bc7f10f2..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.38.0",
+ "@eslint/js": "9.39.1",
"@excalidraw/excalidraw": "0.18.0",
"@fullcalendar/core": "6.1.19",
"@fullcalendar/daygrid": "6.1.19",
@@ -37,12 +37,12 @@
"bootstrap": "5.3.8",
"boxicons": "2.1.4",
"color": "5.0.2",
- "dayjs": "1.11.18",
+ "dayjs": "1.11.19",
"dayjs-plugin-utc": "0.1.2",
- "debounce": "2.2.0",
+ "debounce": "3.0.0",
"draggabilly": "3.0.0",
"force-graph": "1.51.0",
- "globals": "16.4.0",
+ "globals": "16.5.0",
"i18next": "25.6.0",
"i18next-http-backend": "3.0.2",
"jquery": "3.7.1",
@@ -59,7 +59,7 @@
"normalize.css": "8.0.1",
"panzoom": "9.4.3",
"preact": "10.27.2",
- "react-i18next": "16.2.1",
+ "react-i18next": "16.2.4",
"reveal.js": "5.2.1",
"svg-pan-zoom": "3.6.2",
"tabulator-tables": "6.3.1",
@@ -76,7 +76,7 @@
"@types/reveal.js": "5.2.1",
"@types/tabulator-tables": "6.3.0",
"copy-webpack-plugin": "13.0.1",
- "happy-dom": "20.0.8",
+ "happy-dom": "20.0.10",
"script-loader": "0.7.2",
"vite-plugin-static-copy": "3.1.4"
}
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, string | null> = {
file: null,
image: null,
launcher: null,
- mermaid: null,
+ mermaid: "s1aBHPd79XYj",
mindMap: null,
noteMap: null,
relationMap: null,
diff --git a/apps/client/src/services/shortcuts.spec.ts b/apps/client/src/services/shortcuts.spec.ts
index 87f8ae489..b9576025f 100644
--- a/apps/client/src/services/shortcuts.spec.ts
+++ b/apps/client/src/services/shortcuts.spec.ts
@@ -159,7 +159,7 @@ describe("shortcuts", () => {
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/ar/translation.json b/apps/client/src/translations/ar/translation.json
index b04472d7c..dffb4f9d4 100644
--- a/apps/client/src/translations/ar/translation.json
+++ b/apps/client/src/translations/ar/translation.json
@@ -716,7 +716,6 @@
"backup_database_now": "نسخ اختياطي لقاعدة البيانات الان"
},
"etapi": {
- "wiki": "ويكي",
"created": "تم الأنشاء",
"actions": "أجراءات",
"title": "ETAPI",
diff --git a/apps/client/src/translations/cn/translation.json b/apps/client/src/translations/cn/translation.json
index e9738c25a..44aa6d387 100644
--- a/apps/client/src/translations/cn/translation.json
+++ b/apps/client/src/translations/cn/translation.json
@@ -1289,10 +1289,6 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI 是一个 REST API,用于以编程方式访问 Trilium 实例,而无需 UI。",
- "see_more": "有关更多详细信息,请参见 {{- link_to_wiki}} 和 {{- link_to_openapi_spec}} 或 {{- link_to_swagger_ui}}。",
- "wiki": "维基",
- "openapi_spec": "ETAPI OpenAPI 规范",
- "swagger_ui": "ETAPI Swagger UI",
"create_token": "创建新的 ETAPI 令牌",
"existing_tokens": "现有令牌",
"no_tokens_yet": "目前还没有令牌。点击上面的按钮创建一个。",
diff --git a/apps/client/src/translations/de/translation.json b/apps/client/src/translations/de/translation.json
index 6d4790da8..6ff9525ff 100644
--- a/apps/client/src/translations/de/translation.json
+++ b/apps/client/src/translations/de/translation.json
@@ -1286,10 +1286,6 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI ist eine REST-API, die für den programmgesteuerten Zugriff auf die Trilium-Instanz ohne Benutzeroberfläche verwendet wird.",
- "see_more": "Weitere Details können im {{- link_to_wiki}} und in der {{- link_to_openapi_spec}} oder der {{- link_to_swagger_ui }} gefunden werden.",
- "wiki": "Wiki",
- "openapi_spec": "ETAPI OpenAPI-Spezifikation",
- "swagger_ui": "ETAPI Swagger UI",
"create_token": "Erstelle ein neues ETAPI-Token",
"existing_tokens": "Vorhandene Token",
"no_tokens_yet": "Es sind noch keine Token vorhanden. Klicke auf die Schaltfläche oben, um eine zu erstellen.",
diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json
index 78056e19a..f89e42f47 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",
@@ -1453,10 +1456,6 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI is a REST API used to access Trilium instance programmatically, without UI.",
- "see_more": "See more details in the {{- link_to_wiki}} and the {{- link_to_openapi_spec}} or the {{- link_to_swagger_ui }}.",
- "wiki": "wiki",
- "openapi_spec": "ETAPI OpenAPI spec",
- "swagger_ui": "ETAPI Swagger UI",
"create_token": "Create new ETAPI token",
"existing_tokens": "Existing tokens",
"no_tokens_yet": "There are no tokens yet. Click on the button above to create one.",
diff --git a/apps/client/src/translations/es/translation.json b/apps/client/src/translations/es/translation.json
index fe2f00dc0..b83fcf7bb 100644
--- a/apps/client/src/translations/es/translation.json
+++ b/apps/client/src/translations/es/translation.json
@@ -1446,10 +1446,6 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI es una REST API que se utiliza para acceder a la instancia de Trilium mediante programación, sin interfaz de usuario.",
- "see_more": "Véa más detalles en el {{- link_to_wiki}} y el {{- link_to_openapi_spec}} o el {{- link_to_swagger_ui }}.",
- "wiki": "wiki",
- "openapi_spec": "Especificación ETAPI OpenAPI",
- "swagger_ui": "ETAPI Swagger UI",
"create_token": "Crear nuevo token ETAPI",
"existing_tokens": "Tokens existentes",
"no_tokens_yet": "Aún no hay tokens. Dé clic en el botón de arriba para crear uno.",
diff --git a/apps/client/src/translations/fr/translation.json b/apps/client/src/translations/fr/translation.json
index 84593207b..1a4a1dec8 100644
--- a/apps/client/src/translations/fr/translation.json
+++ b/apps/client/src/translations/fr/translation.json
@@ -1288,8 +1288,6 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI est une API REST utilisée pour accéder à l'instance Trilium par programme, sans interface utilisateur.",
- "wiki": "wiki",
- "openapi_spec": "Spec ETAPI OpenAPI",
"create_token": "Créer un nouveau jeton ETAPI",
"existing_tokens": "Jetons existants",
"no_tokens_yet": "Il n'y a pas encore de jetons. Cliquez sur le bouton ci-dessus pour en créer un.",
@@ -1306,9 +1304,7 @@
"delete_token": "Supprimer/désactiver ce token",
"rename_token_title": "Renommer le jeton",
"rename_token_message": "Veuillez saisir le nom du nouveau jeton",
- "delete_token_confirmation": "Êtes-vous sûr de vouloir supprimer le jeton ETAPI « {{name}} » ?",
- "see_more": "Voir plus de détails dans le {{- link_to_wiki}} et le {{- link_to_openapi_spec}} ou le {{- link_to_swagger_ui }}.",
- "swagger_ui": "Interface utilisateur ETAPI Swagger"
+ "delete_token_confirmation": "Êtes-vous sûr de vouloir supprimer le jeton ETAPI « {{name}} » ?"
},
"options_widget": {
"options_status": "Statut des options",
diff --git a/apps/client/src/translations/it/translation.json b/apps/client/src/translations/it/translation.json
index d8bf6bad6..52c029ffb 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.",
@@ -132,10 +133,6 @@
"new_token_message": "Inserisci il nome del nuovo token",
"title": "ETAPI",
"description": "ETAPI è un'API REST utilizzata per accedere alle istanze di Trilium in modo programmatico, senza interfaccia utente.",
- "see_more": "Per maggiori dettagli consulta {{- link_to_wiki}} e {{- link_to_openapi_spec}} o {{- link_to_swagger_ui}}.",
- "wiki": "wiki",
- "openapi_spec": "Specifiche ETAPI OpenAPI",
- "swagger_ui": "Interfaccia utente ETAPI Swagger",
"create_token": "Crea un nuovo token ETAPI",
"existing_tokens": "Token esistenti",
"no_tokens_yet": "Non ci sono ancora token. Clicca sul pulsante qui sopra per crearne uno.",
diff --git a/apps/client/src/translations/ja/translation.json b/apps/client/src/translations/ja/translation.json
index 05c8b48f9..6a9b4f75e 100644
--- a/apps/client/src/translations/ja/translation.json
+++ b/apps/client/src/translations/ja/translation.json
@@ -657,10 +657,6 @@
"created": "作成日時",
"title": "ETAPI",
"description": "ETAPI は、Trilium インスタンスに UI なしでプログラム的にアクセスするための REST API です。",
- "see_more": "詳細は{{- link_to_wiki}}と{{- link_to_openapi_spec}}または{{- link_to_swagger_ui }}を参照してください。",
- "wiki": "wiki",
- "openapi_spec": "ETAPI OpenAPIの仕様",
- "swagger_ui": "ETAPI Swagger UI",
"create_token": "新しくETAPIトークンを作成",
"existing_tokens": "既存のトークン",
"no_tokens_yet": "トークンはまだありません。上のボタンをクリックして作成してください。",
diff --git a/apps/client/src/translations/pl/translation.json b/apps/client/src/translations/pl/translation.json
index 426296d14..6ff4b26f4 100644
--- a/apps/client/src/translations/pl/translation.json
+++ b/apps/client/src/translations/pl/translation.json
@@ -1663,10 +1663,6 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI to interfejs API REST używany do programowego dostępu do instancji Trilium, bez interfejsu użytkownika.",
- "see_more": "Zobacz więcej szczegółów w {{- link_to_wiki}} oraz w {{- link_to_openapi_spec}} lub {{- link_to_swagger_ui }}.",
- "wiki": "wiki",
- "openapi_spec": "specyfikacja ETAPI OpenAPI",
- "swagger_ui": "ETAPI Swagger UI",
"create_token": "Utwórz nowy token ETAPI",
"existing_tokens": "Istniejące tokeny",
"no_tokens_yet": "Nie ma jeszcze żadnych tokenów. Kliknij przycisk powyżej, aby utworzyć jeden.",
diff --git a/apps/client/src/translations/pt/translation.json b/apps/client/src/translations/pt/translation.json
index f386f61e8..5497ad817 100644
--- a/apps/client/src/translations/pt/translation.json
+++ b/apps/client/src/translations/pt/translation.json
@@ -1422,10 +1422,6 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI é uma API REST usada para aceder a instância do Trilium programaticamente, sem interface gráfica.",
- "see_more": "Veja mais pormenores no {{- link_to_wiki}}, na {{- link_to_openapi_spec}} ou na {{- link_to_swagger_ui}}.",
- "wiki": "wiki",
- "openapi_spec": "Especificação OpenAPI do ETAPI",
- "swagger_ui": "ETAPI Swagger UI",
"create_token": "Criar token ETAPI",
"existing_tokens": "Tokens existentes",
"no_tokens_yet": "Ainda não existem tokens. Clique no botão acima para criar um.",
diff --git a/apps/client/src/translations/pt_br/translation.json b/apps/client/src/translations/pt_br/translation.json
index 08d891356..0d1676832 100644
--- a/apps/client/src/translations/pt_br/translation.json
+++ b/apps/client/src/translations/pt_br/translation.json
@@ -1932,10 +1932,6 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI é uma API REST usada para acessar a instância do Trilium programaticamente, sem interface gráfica.",
- "see_more": "Veja mais detalhes no {{- link_to_wiki}}, na {{- link_to_openapi_spec}} ou na {{- link_to_swagger_ui}}.",
- "wiki": "wiki",
- "openapi_spec": "Especificação OpenAPI do ETAPI",
- "swagger_ui": "ETAPI Swagger UI",
"create_token": "Criar novo token ETAPI",
"existing_tokens": "Tokens existentes",
"no_tokens_yet": "Ainda não existem tokens. Clique no botão acima para criar um.",
diff --git a/apps/client/src/translations/ro/translation.json b/apps/client/src/translations/ro/translation.json
index c683aba59..dd8947003 100644
--- a/apps/client/src/translations/ro/translation.json
+++ b/apps/client/src/translations/ro/translation.json
@@ -507,17 +507,13 @@
"new_token_message": "Introduceți denumirea noului token",
"new_token_title": "Token ETAPI nou",
"no_tokens_yet": "Nu există încă token-uri. Clic pe butonul de deasupra pentru a crea una.",
- "openapi_spec": "Specificația OpenAPI pentru ETAPI",
- "swagger_ui": "UI-ul Swagger pentru ETAPI",
"rename_token": "Redenumește token-ul",
"rename_token_message": "Introduceți denumirea noului token",
"rename_token_title": "Redenumire token",
- "see_more": "Vedeți mai multe detalii în {{- link_to_wiki}} și în {{- link_to_openapi_spec}} sau în {{- link_to_swagger_ui }}.",
"title": "ETAPI",
"token_created_message": "Copiați token-ul creat în clipboard. Trilium stochează token-ul ca hash așadar această valoare poate fi văzută doar acum.",
"token_created_title": "Token ETAPI creat",
- "token_name": "Denumire token",
- "wiki": "wiki"
+ "token_name": "Denumire token"
},
"execute_script": {
"example_1": "De exemplu, pentru a adăuga un șir de caractere la titlul unei notițe, se poate folosi acest mic script:",
diff --git a/apps/client/src/translations/ru/translation.json b/apps/client/src/translations/ru/translation.json
index c1e62e327..adc2bab50 100644
--- a/apps/client/src/translations/ru/translation.json
+++ b/apps/client/src/translations/ru/translation.json
@@ -1440,7 +1440,6 @@
},
"etapi": {
"title": "ETAPI",
- "wiki": "вики",
"created": "Создано",
"actions": "Действия",
"existing_tokens": "Существующие токены",
@@ -1448,10 +1447,7 @@
"default_token_name": "новый токен",
"rename_token_title": "Переименовать токен",
"description": "ETAPI — это REST API, используемый для программного доступа к экземпляру Trilium без пользовательского интерфейса.",
- "see_more": "Более подробную информацию смотрите в {{- link_to_wiki}} и {{- link_to_openapi_spec}} или {{- link_to_swagger_ui }}.",
"create_token": "Создать новый токен ETAPI",
- "openapi_spec": "Спецификация ETAPI OpenAPI",
- "swagger_ui": "Пользовательский интерфейс ETAPI Swagger",
"new_token_title": "Новый токен ETAPI",
"token_created_title": "Создан токен ETAPI",
"rename_token": "Переименовать этот токен",
diff --git a/apps/client/src/translations/tw/translation.json b/apps/client/src/translations/tw/translation.json
index e31228844..2ba0f9afd 100644
--- a/apps/client/src/translations/tw/translation.json
+++ b/apps/client/src/translations/tw/translation.json
@@ -1281,8 +1281,6 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI 是一個 REST API,用於以編程方式訪問 Trilium 實例,而無需 UI。",
- "wiki": "維基",
- "openapi_spec": "ETAPI OpenAPI 規範",
"create_token": "新增 ETAPI 令牌",
"existing_tokens": "現有令牌",
"no_tokens_yet": "目前還沒有令牌。點擊上面的按鈕新增一個。",
@@ -1299,9 +1297,7 @@
"delete_token": "刪除 / 停用此令牌",
"rename_token_title": "重新命名令牌",
"rename_token_message": "請輸入新的令牌名稱",
- "delete_token_confirmation": "您確定要刪除 ETAPI 令牌 \"{{name}}\" 嗎?",
- "see_more": "有關更多詳細資訊,請參閱 {{- link_to_wiki}} 和 {{- link_to_openapi_spec}} 或 {{- link_to_swagger_ui}}。",
- "swagger_ui": "ETAPI Swagger UI"
+ "delete_token_confirmation": "您確定要刪除 ETAPI 令牌 \"{{name}}\" 嗎?"
},
"options_widget": {
"options_status": "選項狀態",
diff --git a/apps/client/src/translations/uk/translation.json b/apps/client/src/translations/uk/translation.json
index 9c2a1eca1..ebddac41b 100644
--- a/apps/client/src/translations/uk/translation.json
+++ b/apps/client/src/translations/uk/translation.json
@@ -1402,10 +1402,6 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI — це REST API, який використовується для програмного доступу до екземпляра Trilium без інтерфейсу користувача.",
- "see_more": "Див. докладнішу інформацію у {{- link_to_wiki}} та {{- link_to_openapi_spec}} або {{- link_to_swagger_ui }}.",
- "wiki": "вікі",
- "openapi_spec": "ETAPI OpenAPI spec",
- "swagger_ui": "ETAPI Swagger UI",
"create_token": "Створити новий токен ETAPI",
"existing_tokens": "Існуючі токени",
"no_tokens_yet": "Токенів поки що немає. Натисніть кнопку вище, щоб створити його.",
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() {
+ {!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/components/OptionsSection.tsx b/apps/client/src/widgets/type_widgets/options/components/OptionsSection.tsx
index ff78d8a33..ce42b66e3 100644
--- a/apps/client/src/widgets/type_widgets/options/components/OptionsSection.tsx
+++ b/apps/client/src/widgets/type_widgets/options/components/OptionsSection.tsx
@@ -2,7 +2,7 @@ import type { ComponentChildren } from "preact";
import { CSSProperties } from "preact/compat";
interface OptionsSectionProps {
- title?: string;
+ title?: ComponentChildren;
children: ComponentChildren;
noCard?: boolean;
style?: CSSProperties;
diff --git a/apps/client/src/widgets/type_widgets/options/etapi.tsx b/apps/client/src/widgets/type_widgets/options/etapi.tsx
index 3ee7c7e19..f49dc85f7 100644
--- a/apps/client/src/widgets/type_widgets/options/etapi.tsx
+++ b/apps/client/src/widgets/type_widgets/options/etapi.tsx
@@ -11,6 +11,7 @@ import dialog from "../../../services/dialog";
import { formatDateTime } from "../../../utils/formatters";
import ActionButton from "../../react/ActionButton";
import { useTriliumEvent } from "../../react/hooks";
+import HelpButton from "../../react/HelpButton";
type RenameTokenCallback = (tokenId: string, oldName: string) => Promise;
type DeleteTokenCallback = (tokenId: string, name: string ) => Promise;
@@ -48,19 +49,13 @@ export default function EtapiSettings() {
message: t("etapi.token_created_message"),
defaultValue: authToken
});
- }, []);
+ }, []);
return (
- {t("etapi.description")}
- ${t("etapi.wiki")}`,
- // TODO: We use window.open src/public/app/services/link.ts -> prevents regular click behavior on "a" element here because it's a relative path
- link_to_openapi_spec: `${t("etapi.openapi_spec")} `,
- link_to_swagger_ui: `${t("etapi.swagger_ui")} `
- })} />
+ {t("etapi.description")}
+
+
{t("etapi.existing_tokens")}
@@ -123,7 +119,7 @@ function TokenList({ tokens }: { tokens: EtapiToken[] }) {
text={t("etapi.rename_token")}
onClick={() => renameCallback(etapiTokenId, name)}
/>
-
+
-
-
+
+
);
}
diff --git a/apps/desktop/package.json b/apps/desktop/package.json
index a59f17e12..5cf38b041 100644
--- a/apps/desktop/package.json
+++ b/apps/desktop/package.json
@@ -35,7 +35,7 @@
"@triliumnext/commons": "workspace:*",
"@triliumnext/server": "workspace:*",
"copy-webpack-plugin": "13.0.1",
- "electron": "38.4.0",
+ "electron": "38.5.0",
"@electron-forge/cli": "7.10.2",
"@electron-forge/maker-deb": "7.10.2",
"@electron-forge/maker-dmg": "7.10.2",
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:
-
First Item
@@ -56,7 +50,6 @@
Unordered:
-
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 blocks and
code blocks and 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.
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 @@
+
+
+