Merge branch 'develop' into chore_npm-scripts-namescape

This commit is contained in:
Panagiotis Papadopoulos 2025-02-15 09:02:23 +01:00
commit 11a9dfd693
90 changed files with 1734 additions and 442 deletions

View File

@ -1,5 +1,5 @@
# Build stage
FROM node:22.13.1-bullseye-slim AS builder
FROM node:22.14.0-bullseye-slim AS builder
# Configure build dependencies in a single layer
RUN apt-get update && apt-get install -y --no-install-recommends \
@ -36,7 +36,7 @@ RUN cp -R build/src/* src/. && \
rm -r build
# Runtime stage
FROM node:22.13.1-bullseye-slim
FROM node:22.14.0-bullseye-slim
# Install only runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \

View File

@ -1,5 +1,5 @@
# Build stage
FROM node:22.13.1-alpine AS builder
FROM node:22.14.0-alpine AS builder
# Configure build dependencies
RUN apk add --no-cache --virtual .build-dependencies \
@ -35,7 +35,7 @@ RUN cp -R build/src/* src/. && \
rm -r build
# Runtime stage
FROM node:22.13.1-alpine
FROM node:22.14.0-alpine
# Install runtime dependencies
RUN apk add --no-cache su-exec shadow

View File

@ -29,7 +29,12 @@ const copy = async () => {
fs.copySync(path.join("build", srcFile), destFile, { recursive: true });
}
const filesToCopy = ["config-sample.ini", "tsconfig.webpack.json", "./src/etapi/etapi.openapi.yaml"];
const filesToCopy = [
"config-sample.ini",
"tsconfig.webpack.json",
"./src/etapi/etapi.openapi.yaml",
"./src/routes/api/openapi.json"
];
for (const file of filesToCopy) {
log(`Copying ${file}`);
await fs.copy(file, path.join(DEST_DIR, file));

View File

@ -1,51 +0,0 @@
import swaggerJsdoc from 'swagger-jsdoc';
/*
* Usage: npm run generate-openapi | tail -n1 > x.json
*
* Inspect generated file by opening it in https://editor-next.swagger.io/
*
*/
const options = {
definition: {
openapi: '3.1.1',
info: {
title: 'Trilium Notes - Sync server API',
version: '0.96.6',
description: "This is the internal sync server API used by Trilium Notes / TriliumNext Notes.\n\n_If you're looking for the officially supported External Trilium API, see [here](https://triliumnext.github.io/Docs/Wiki/etapi.html)._\n\nThis page does not yet list all routes. For a full list, see the [route controller](https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/routes.ts).",
contact: {
name: "TriliumNext issue tracker",
url: "https://github.com/TriliumNext/Notes/issues",
},
license: {
name: "GNU Free Documentation License 1.3 (or later)",
url: "https://www.gnu.org/licenses/fdl-1.3",
},
},
},
apis: ['./src/routes/api/*.ts', './bin/generate-openapi.js'],
};
const openapiSpecification = swaggerJsdoc(options);
console.log(JSON.stringify(openapiSpecification));
/**
* @swagger
* components:
* schemas:
* UtcDateTime:
* type: string
* example: "2025-02-13T07:42:47.698Z"
* securitySchemes:
* user-password:
* type: apiKey
* name: trilium-cred
* in: header
* description: "Username and password, formatted as `user:password`"
* session:
* type: apiKey
* in: cookie
* name: trilium.sid
*/

189
bin/generate-openapi.ts Normal file
View File

@ -0,0 +1,189 @@
import { fileURLToPath } from "url";
import { dirname, join } from "path";
import swaggerJsdoc from 'swagger-jsdoc';
import fs from "fs";
/*
* Usage: npm run generate-openapi | tail -n1 > x.json
*
* Inspect generated file by opening it in https://editor-next.swagger.io/
*
*/
const options = {
definition: {
openapi: '3.1.1',
info: {
title: 'Trilium Notes - Sync server API',
version: '0.96.6',
description: "This is the internal sync server API used by Trilium Notes / TriliumNext Notes.\n\n_If you're looking for the officially supported External Trilium API, see [here](https://triliumnext.github.io/Docs/Wiki/etapi.html)._\n\nThis page does not yet list all routes. For a full list, see the [route controller](https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/routes.ts).",
contact: {
name: "TriliumNext issue tracker",
url: "https://github.com/TriliumNext/Notes/issues",
},
license: {
name: "GNU Free Documentation License 1.3 (or later)",
url: "https://www.gnu.org/licenses/fdl-1.3",
},
},
},
apis: [
// Put individual files here to have them ordered first.
'./src/routes/api/setup.ts',
// all other files
'./src/routes/api/*.ts', './bin/generate-openapi.js'
],
};
const openapiSpecification = swaggerJsdoc(options);
const scriptDir = dirname(fileURLToPath(import.meta.url));
const outputPath = join(scriptDir, "..", "src", "routes", "api", "openapi.json");
fs.writeFileSync(outputPath, JSON.stringify(openapiSpecification));
console.log("Saved to ", outputPath);
/**
* @swagger
* tags:
* - name: auth
* description: Authentication
* - name: sync
* description: Synchronization
* - name: data
*/
/**
* @swagger
* components:
* schemas:
* Attribute:
* type: object
* properties:
* attributeId:
* type: string
* example: "4G1DPrI58PAb"
* noteId:
* $ref: "#/components/schemas/NoteId"
* type:
* type: string
* enum: ["attribute", "relation"]
* name:
* type: string
* example: "internalLink"
* value:
* type: string
* example: "hA8aHSpTRdZ6"
* description: "If type = \"relation\", a note ID. Otherwise, the attribute content."
* position:
* type: integer
* example: 20
* isInheritable:
* type: boolean
* Blob:
* type: object
* properties:
* blobId:
* type: string
* example: "8iqMIB8eiY1tPYmElfjm"
* content:
* type:
* - string
* - 'null'
* description: "`null` if not text."
* contentLength:
* type: integer
* dateModified:
* $ref: "#/components/schemas/DateTime"
* utcDateModified:
* $ref: "#/components/schemas/UtcDateTime"
* Branch:
* type: object
* properties:
* branchId:
* $ref: "#/components/schemas/BranchId"
* noteId:
* $ref: "#/components/schemas/NoteId"
* parentNoteId:
* $ref: "#/components/schemas/NoteId"
* notePosition:
* type: integer
* example: 20
* prefix:
* type:
* - string
* - 'null'
* isExpanded:
* type: boolean
* BranchId:
* type: string
* example: "WUjhaGp4EKah_ur11rSfHkzeV"
* description: Equal to `{parentNoteId}_{noteId}`
* DateTime:
* type: string
* example: "2025-02-14 08:19:59.203+0100"
* EntityChange:
* type: object
* properties:
* entityChange:
* type: object
* properties:
* entityName:
* type: string
* example: "notes"
* description: Database table for this entity.
* changeId:
* type: string
* example: "changeId9630"
* description: ID, referenced in `entity_changes` table.
* entity:
* type: object
* description: Encoded entity data. Object has one property for each database column.
* Note:
* type: object
* properties:
* noteId:
* $ref: "#/components/schemas/NoteId"
* title:
* type: string
* isProtected:
* type: boolean
* type:
* type: string
* example: "text"
* enum: ["text", "code", "render", "file", "image", "search", "relationMap", "book", "noteMap", "mermaid", "canvas", "webView", "launcher", "doc", "contentWidget", "mindMap", "geoMap"]
* description: "[Reference list](https://github.com/TriliumNext/Notes/blob/v0.91.6/src/services/note_types.ts)"
* mime:
* type: string
* example: "text/html"
* blobId:
* type: string
* example: "z4PhNX7vuL3xVChQ1m2A"
* NoteId:
* type: string
* example: "ur11rSfHkzeV"
* description: "12-character note ID. Special values: \"none\"`, `\"root\"."
* Timestamps:
* type: object
* properties:
* dateCreated:
* $ref: "#/components/schemas/DateTime"
* dateModified:
* $ref: "#/components/schemas/DateTime"
* utcDateCreated:
* $ref: "#/components/schemas/UtcDateTime"
* utcDateModified:
* $ref: "#/components/schemas/UtcDateTime"
* UtcDateTime:
* type: string
* example: "2025-02-13T07:42:47.698Z"
* description: "Result of `new Date().toISOString().replace('T', ' ')`"
* securitySchemes:
* user-password:
* type: apiKey
* name: trilium-cred
* in: header
* description: "Username and password, formatted as `user:password`"
* session:
* type: apiKey
* in: cookie
* name: trilium.sid
*/

283
package-lock.json generated
View File

@ -135,13 +135,12 @@
"@types/fs-extra": "11.0.4",
"@types/html": "1.0.4",
"@types/ini": "4.1.1",
"@types/jasmine": "5.1.5",
"@types/jquery": "3.5.32",
"@types/jsdom": "21.1.7",
"@types/leaflet-gpx": "1.3.7",
"@types/mime-types": "2.1.4",
"@types/multer": "1.4.12",
"@types/node": "22.13.1",
"@types/node": "22.13.4",
"@types/react": "18.3.18",
"@types/safe-compare": "1.1.2",
"@types/sanitize-html": "2.13.0",
@ -157,12 +156,12 @@
"@types/yargs": "17.0.33",
"@vitest/coverage-v8": "3.0.5",
"cross-env": "7.0.3",
"electron": "34.1.1",
"electron": "34.2.0",
"esm": "3.2.25",
"jsdoc": "4.0.4",
"lorem-ipsum": "2.0.8",
"nodemon": "3.1.9",
"prettier": "3.5.0",
"prettier": "3.5.1",
"rcedit": "4.0.1",
"rimraf": "6.0.1",
"swagger-jsdoc": "6.2.8",
@ -171,7 +170,7 @@
"typedoc": "0.27.7",
"typescript": "5.7.3",
"vitest": "3.0.5",
"webpack": "5.97.1",
"webpack": "5.98.0",
"webpack-cli": "6.0.1",
"webpack-dev-middleware": "7.4.2"
}
@ -4104,13 +4103,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/jasmine": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.5.tgz",
"integrity": "sha512-SaCZ3kM5NjOiJqMRYwHpLbTfUC2Dyk1KS3QanNFsUYPGTk70CWVK/J9ueun6zNhw/UkgV7xl8V4ZLQZNRbfnNw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/jquery": {
"version": "3.5.32",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.32.tgz",
@ -4239,9 +4231,9 @@
}
},
"node_modules/@types/node": {
"version": "22.13.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz",
"integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==",
"version": "22.13.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz",
"integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
@ -4970,15 +4962,15 @@
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
@ -5002,35 +4994,16 @@
}
}
},
"node_modules/ajv-formats/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"node_modules/ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
"fast-deep-equal": "^3.1.3"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"license": "MIT",
"peerDependencies": {
"ajv": "^6.9.1"
"ajv": "^8.8.2"
}
},
"node_modules/amator": {
@ -8004,9 +7977,9 @@
}
},
"node_modules/electron": {
"version": "34.1.1",
"resolved": "https://registry.npmjs.org/electron/-/electron-34.1.1.tgz",
"integrity": "sha512-1aDYk9Gsv1/fFeClMrxWGoVMl7uCUgl1pe26BiTnLXmAoqEXCa3f3sCKFWV+cuDzUjQGAZcpkWhGYTgWUSQrLA==",
"version": "34.2.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-34.2.0.tgz",
"integrity": "sha512-SYwBJNeXBTm1q/ErybQMUBZAYqEreBUqBwTrNkw1rV4YatDZk5Aittpcus3PPeC4UoI/tqmJ946uG8AKHTd6CA==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@ -8725,9 +8698,9 @@
}
},
"node_modules/electron/node_modules/@types/node": {
"version": "20.17.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.17.tgz",
"integrity": "sha512-/WndGO4kIfMicEQLTi/mDANUu/iVUhT7KboZPdEqqHQ4aTS+3qT3U5gIqWDFV+XouorjfgGqvKILJeHhuQgFYg==",
"version": "20.17.19",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.19.tgz",
"integrity": "sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
@ -9027,6 +9000,28 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/eslint-scope/node_modules/estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=4.0"
}
},
"node_modules/esm": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
@ -9547,12 +9542,6 @@
"node": ">= 6"
}
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"license": "MIT"
},
"node_modules/fast-uri": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz",
@ -11707,9 +11696,9 @@
"license": "MIT"
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/json-stringify-safe": {
@ -14000,9 +13989,9 @@
}
},
"node_modules/prettier": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.0.tgz",
"integrity": "sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==",
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz",
"integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==",
"dev": true,
"license": "MIT",
"bin": {
@ -15215,14 +15204,15 @@
}
},
"node_modules/schema-utils": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
"integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.1.0"
},
"engines": {
"node": ">= 10.13.0"
@ -16502,59 +16492,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/terser-webpack-plugin/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/terser-webpack-plugin/node_modules/ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3"
},
"peerDependencies": {
"ajv": "^8.8.2"
}
},
"node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/terser-webpack-plugin/node_modules/schema-utils": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
"integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.1.0"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@ -17295,15 +17232,6 @@
"browserslist": ">= 4.21.0"
}
},
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"license": "BSD-2-Clause",
"dependencies": {
"punycode": "^2.1.0"
}
},
"node_modules/username": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/username/-/username-5.1.0.tgz",
@ -18149,9 +18077,9 @@
}
},
"node_modules/webpack": {
"version": "5.97.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz",
"integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==",
"version": "5.98.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz",
"integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==",
"license": "MIT",
"dependencies": {
"@types/eslint-scope": "^3.7.7",
@ -18172,9 +18100,9 @@
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
"schema-utils": "^3.2.0",
"schema-utils": "^4.3.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.3.10",
"terser-webpack-plugin": "^5.3.11",
"watchpack": "^2.4.1",
"webpack-sources": "^3.2.3"
},
@ -18277,63 +18205,6 @@
}
}
},
"node_modules/webpack-dev-middleware/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/webpack-dev-middleware/node_modules/ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3"
},
"peerDependencies": {
"ajv": "^8.8.2"
}
},
"node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT"
},
"node_modules/webpack-dev-middleware/node_modules/schema-utils": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
"integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.1.0"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/webpack-merge": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz",
@ -18358,28 +18229,6 @@
"node": ">=10.13.0"
}
},
"node_modules/webpack/node_modules/eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/webpack/node_modules/estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=4.0"
}
},
"node_modules/whatwg-encoding": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",

View File

@ -49,8 +49,8 @@
"build:webpack": "tsx node_modules/webpack/bin/webpack.js -c webpack.config.ts",
"build:prepare-dist": "rimraf ./dist && tsc && tsx ./bin/copy-dist.ts",
"test": "cross-env TRILIUM_DATA_DIR=./data-test vitest",
"test:coverage": "cross-env TRILIUM_DATA_DIR=./data-test vitest --coverage",
"test": "cross-env TRILIUM_DATA_DIR=./integration-tests/db vitest",
"test:coverage": "cross-env TRILIUM_DATA_DIR=./integration-tests/db vitest --coverage",
"test:playwright": "playwright test",
"test:integration-edit-db": "cross-env TRILIUM_INTEGRATION_TEST=edit TRILIUM_PORT=8081 TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
@ -64,7 +64,7 @@
"chore:update-build-info": "tsx bin/update-build-info.ts",
"chore:ci-update-nightly-version": "tsx ./bin/update-nightly-version.ts",
"chore:generate-document": "cross-env nodemon ./bin/generate_document.ts 1000",
"chore:generate-openapi": "node bin/generate-openapi.js"
"chore:generate-openapi": "tsx bin/generate-openapi.js"
},
"dependencies": {
"@braintree/sanitize-url": "7.1.1",
@ -190,13 +190,12 @@
"@types/fs-extra": "11.0.4",
"@types/html": "1.0.4",
"@types/ini": "4.1.1",
"@types/jasmine": "5.1.5",
"@types/jquery": "3.5.32",
"@types/jsdom": "21.1.7",
"@types/leaflet-gpx": "1.3.7",
"@types/mime-types": "2.1.4",
"@types/multer": "1.4.12",
"@types/node": "22.13.1",
"@types/node": "22.13.4",
"@types/react": "18.3.18",
"@types/safe-compare": "1.1.2",
"@types/sanitize-html": "2.13.0",
@ -212,12 +211,12 @@
"@types/yargs": "17.0.33",
"@vitest/coverage-v8": "3.0.5",
"cross-env": "7.0.3",
"electron": "34.1.1",
"electron": "34.2.0",
"esm": "3.2.25",
"jsdoc": "4.0.4",
"lorem-ipsum": "2.0.8",
"nodemon": "3.1.9",
"prettier": "3.5.0",
"prettier": "3.5.1",
"rcedit": "4.0.1",
"rimraf": "6.0.1",
"swagger-jsdoc": "6.2.8",
@ -226,7 +225,7 @@
"typedoc": "0.27.7",
"typescript": "5.7.3",
"vitest": "3.0.5",
"webpack": "5.97.1",
"webpack": "5.98.0",
"webpack-cli": "6.0.1",
"webpack-dev-middleware": "7.4.2"
}

View File

@ -1,8 +1,9 @@
import etapi from "../support/etapi.js";
/* TriliumNextTODO: port to Vitest
etapi.describeEtapi("app_info", () => {
it("get", async () => {
const appInfo = await etapi.getEtapi("app-info");
expect(appInfo.clipperProtocolVersion).toEqual("1.0");
});
});
*/

View File

@ -1,8 +1,10 @@
import etapi from "../support/etapi.js";
/* TriliumNextTODO: port to Vitest
etapi.describeEtapi("backup", () => {
it("create", async () => {
const response = await etapi.putEtapiContent("backup/etapi_test");
expect(response.status).toEqual(204);
});
});
*/

View File

@ -3,6 +3,7 @@ import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
/* TriliumNextTODO: port to Vitest
etapi.describeEtapi("import", () => {
// temporarily skip this test since test-export.zip is missing
xit("import", async () => {
@ -22,3 +23,4 @@ etapi.describeEtapi("import", () => {
expect(content).toContain("test export content");
});
});
*/

View File

@ -1,6 +1,7 @@
import crypto from "crypto";
import etapi from "../support/etapi.js";
/* TriliumNextTODO: port to Vitest
etapi.describeEtapi("notes", () => {
it("create", async () => {
const { note, branch } = await etapi.postEtapi("create-note", {
@ -99,3 +100,4 @@ etapi.describeEtapi("notes", () => {
expect(error.message).toEqual(`Note '${note.noteId}' not found.`);
});
});
*/

View File

@ -1,4 +1,5 @@
import type child_process from "child_process";
import { describe, beforeAll, afterAll } from "vitest";
let etapiAuthToken: string | undefined;

View File

@ -1,6 +1,6 @@
{
"formatVersion": 2,
"appVersion": "0.91.5",
"appVersion": "0.91.6-test-250214-024424",
"files": [
{
"isClone": false,
@ -11,7 +11,7 @@
"title": "User Guide",
"notePosition": 20,
"prefix": null,
"isExpanded": false,
"isExpanded": true,
"type": "text",
"mime": "text/html",
"attributes": [
@ -29,22 +29,326 @@
"children": [
{
"isClone": false,
"noteId": "wmegHv51MJMd",
"noteId": "jrai60LsOhdk",
"notePath": [
"OkOZllzB3fqN",
"wmegHv51MJMd"
"jrai60LsOhdk"
],
"title": "Types of notes",
"title": "Installation",
"notePosition": 20,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
{
"type": "relation",
"name": "internalLink",
"value": "KPeRqBU7YSAY",
"isInheritable": false,
"position": 10
},
{
"type": "label",
"name": "hideChildrenOverview",
"value": "",
"isInheritable": false,
"position": 10
}
],
"format": "html",
"dataFileName": "Installation.html",
"attachments": [
{
"attachmentId": "Mp9RaDeLtETz",
"title": "Fedora_logo.svg",
"role": "image",
"mime": "image/svg+xml",
"position": 10,
"dataFileName": "Installation_Fedora_logo.svg"
}
],
"dirFileName": "Installation",
"children": [
{
"isClone": false,
"noteId": "KPeRqBU7YSAY",
"notePath": [
"OkOZllzB3fqN",
"jrai60LsOhdk",
"KPeRqBU7YSAY"
],
"title": "On Fedora Linux",
"notePosition": 10,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
{
"type": "label",
"name": "iconClass",
"value": "bx bxl-tux",
"isInheritable": false,
"position": 10
}
],
"format": "html",
"dataFileName": "On Fedora Linux.html",
"attachments": [
{
"attachmentId": "YHD8kyEhgkyZ",
"title": "Screenshot From 2025-02-05 19-30-50.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "On Fedora Linux_Screenshot.png"
},
{
"attachmentId": "0CpZ5v5xUMia",
"title": "Screenshot From 2025-02-05 19-35-45.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "1_On Fedora Linux_Screenshot.png"
},
{
"attachmentId": "9u7nBYvUbXJW",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "On Fedora Linux_image.png"
},
{
"attachmentId": "ipGBq0moRvF3",
"title": "Screenshot From 2025-02-05 19-36-27.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "2_On Fedora Linux_Screenshot.png"
},
{
"attachmentId": "fa83WbDUIB4G",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "1_On Fedora Linux_image.png"
},
{
"attachmentId": "kcCWr0YXytOU",
"title": "Screenshot From 2025-02-05 19-30-30.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "3_On Fedora Linux_Screenshot.png"
},
{
"attachmentId": "YF3JZy1qz7Fq",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "2_On Fedora Linux_image.png"
}
]
}
]
},
{
"isClone": false,
"noteId": "yoAe4jV2yzbd",
"notePath": [
"OkOZllzB3fqN",
"yoAe4jV2yzbd"
],
"title": "Features",
"notePosition": 40,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"attachments": [],
"dirFileName": "Types of notes",
"dirFileName": "Features",
"children": [
{
"isClone": false,
"noteId": "13D1lOc9sqmZ",
"notePath": [
"OkOZllzB3fqN",
"yoAe4jV2yzbd",
"13D1lOc9sqmZ"
],
"title": "Export as PDF",
"notePosition": 20,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"dataFileName": "Export as PDF.html",
"attachments": [
{
"attachmentId": "xsGM34t8ssKV",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "Export as PDF_image.png"
},
{
"attachmentId": "cvyes4f1Vhmm",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "1_Export as PDF_image.png"
},
{
"attachmentId": "b3v1pLE6TF1Y",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "2_Export as PDF_image.png"
}
]
},
{
"isClone": false,
"noteId": "B3YLYM4erjnW",
"notePath": [
"OkOZllzB3fqN",
"yoAe4jV2yzbd",
"B3YLYM4erjnW"
],
"title": "Zen mode",
"notePosition": 30,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"dataFileName": "Zen mode.html",
"attachments": [
{
"attachmentId": "TS5MS8fQ8Rfr",
"title": "image.png",
"role": "image",
"mime": "image/jpg",
"position": 10,
"dataFileName": "Zen mode_image.png"
},
{
"attachmentId": "cswryNtIFZHy",
"title": "image.png",
"role": "image",
"mime": "image/jpg",
"position": 10,
"dataFileName": "1_Zen mode_image.png"
},
{
"attachmentId": "UDk4M7uiTE7w",
"title": "image.png",
"role": "image",
"mime": "image/jpg",
"position": 10,
"dataFileName": "2_Zen mode_image.png"
},
{
"attachmentId": "sQldbByAmE0k",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "3_Zen mode_image.png"
},
{
"attachmentId": "DzrJD3hXJwXJ",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "4_Zen mode_image.png"
},
{
"attachmentId": "HeGfp8wObFO5",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "5_Zen mode_image.png"
},
{
"attachmentId": "uWsrFwgfypsS",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "6_Zen mode_image.png"
},
{
"attachmentId": "hX8xmbxgSNFh",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "7_Zen mode_image.png"
}
]
}
]
},
{
"isClone": false,
"noteId": "wmegHv51MJMd",
"notePath": [
"OkOZllzB3fqN",
"wmegHv51MJMd"
],
"title": "Note Types",
"notePosition": 70,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"attachments": [],
"dirFileName": "Note Types",
"children": [
{
"isClone": false,
"noteId": "TTWESa9YFyB4",
"notePath": [
"OkOZllzB3fqN",
"wmegHv51MJMd",
"TTWESa9YFyB4"
],
"title": "Mermaid Diagram",
"notePosition": 10,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
{
"type": "label",
"name": "iconClass",
"value": "bx bx-shape-square",
"isInheritable": false,
"position": 10
}
],
"format": "html",
"dataFileName": "Mermaid Diagram.html",
"attachments": []
},
{
"isClone": false,
"noteId": "foPEtsL51pD2",
@ -54,7 +358,7 @@
"foPEtsL51pD2"
],
"title": "Geo map",
"notePosition": 10,
"notePosition": 20,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -72,7 +376,7 @@
"dataFileName": "Geo map.html",
"attachments": [
{
"attachmentId": "viN50n5G4kB0",
"attachmentId": "J0baLTpafs7C",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -80,7 +384,7 @@
"dataFileName": "Geo map_image.png"
},
{
"attachmentId": "eUrcqc8RRuZG",
"attachmentId": "kcYjOvJDFkbS",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -88,7 +392,7 @@
"dataFileName": "1_Geo map_image.png"
},
{
"attachmentId": "1quk4yxJpeHZ",
"attachmentId": "FDP3JzIVSnuJ",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -96,7 +400,7 @@
"dataFileName": "2_Geo map_image.png"
},
{
"attachmentId": "mgwGrtQZjxxb",
"attachmentId": "eUrcqc8RRuZG",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -104,7 +408,7 @@
"dataFileName": "3_Geo map_image.png"
},
{
"attachmentId": "JULizn130rVI",
"attachmentId": "0AwaQMqt3FVA",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -112,7 +416,7 @@
"dataFileName": "4_Geo map_image.png"
},
{
"attachmentId": "kcYjOvJDFkbS",
"attachmentId": "1quk4yxJpeHZ",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -120,7 +424,7 @@
"dataFileName": "5_Geo map_image.png"
},
{
"attachmentId": "ut6vm2aXVfXI",
"attachmentId": "iSpyhQ5Ya6Nk",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -128,7 +432,7 @@
"dataFileName": "6_Geo map_image.png"
},
{
"attachmentId": "0AwaQMqt3FVA",
"attachmentId": "ut6vm2aXVfXI",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -136,7 +440,7 @@
"dataFileName": "7_Geo map_image.png"
},
{
"attachmentId": "gFR2Izzp18LQ",
"attachmentId": "uYdb9wWf5Nuv",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -144,7 +448,7 @@
"dataFileName": "8_Geo map_image.png"
},
{
"attachmentId": "PMqmCbNLlZOG",
"attachmentId": "GhHYO2LteDmZ",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -152,7 +456,7 @@
"dataFileName": "9_Geo map_image.png"
},
{
"attachmentId": "pKdtiq4r0eFY",
"attachmentId": "viN50n5G4kB0",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -160,7 +464,7 @@
"dataFileName": "10_Geo map_image.png"
},
{
"attachmentId": "FXRVvYpOxWyR",
"attachmentId": "mgwGrtQZjxxb",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -168,7 +472,7 @@
"dataFileName": "11_Geo map_image.png"
},
{
"attachmentId": "42AncDs7SSAf",
"attachmentId": "PMqmCbNLlZOG",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -184,7 +488,7 @@
"dataFileName": "13_Geo map_image.png"
},
{
"attachmentId": "FDP3JzIVSnuJ",
"attachmentId": "JULizn130rVI",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -192,7 +496,7 @@
"dataFileName": "14_Geo map_image.png"
},
{
"attachmentId": "GhHYO2LteDmZ",
"attachmentId": "MdC0DpifJwu4",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -200,7 +504,7 @@
"dataFileName": "15_Geo map_image.png"
},
{
"attachmentId": "J0baLTpafs7C",
"attachmentId": "gFR2Izzp18LQ",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -208,7 +512,7 @@
"dataFileName": "16_Geo map_image.png"
},
{
"attachmentId": "uYdb9wWf5Nuv",
"attachmentId": "42AncDs7SSAf",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -216,7 +520,7 @@
"dataFileName": "17_Geo map_image.png"
},
{
"attachmentId": "iSpyhQ5Ya6Nk",
"attachmentId": "pKdtiq4r0eFY",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -224,7 +528,7 @@
"dataFileName": "18_Geo map_image.png"
},
{
"attachmentId": "MdC0DpifJwu4",
"attachmentId": "FXRVvYpOxWyR",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -237,13 +541,13 @@
},
{
"isClone": false,
"noteId": "BDEpqZHDS51s",
"noteId": "BhLd0mxKn0gY",
"notePath": [
"OkOZllzB3fqN",
"BDEpqZHDS51s"
"BhLd0mxKn0gY"
],
"title": "Working with notes",
"notePosition": 30,
"title": "Shared notes",
"notePosition": 100,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -251,17 +555,17 @@
"attributes": [],
"format": "html",
"attachments": [],
"dirFileName": "Working with notes",
"dirFileName": "Shared notes",
"children": [
{
"isClone": false,
"noteId": "13D1lOc9sqmZ",
"noteId": "1DtQ2mHreeOI",
"notePath": [
"OkOZllzB3fqN",
"BDEpqZHDS51s",
"13D1lOc9sqmZ"
"BhLd0mxKn0gY",
"1DtQ2mHreeOI"
],
"title": "Exporting as PDF",
"title": "Serving directly the content of a note",
"notePosition": 10,
"prefix": null,
"isExpanded": false,
@ -269,31 +573,23 @@
"mime": "text/html",
"attributes": [],
"format": "html",
"dataFileName": "Exporting as PDF.html",
"dataFileName": "Serving directly the content o.html",
"attachments": [
{
"attachmentId": "b3v1pLE6TF1Y",
"attachmentId": "2zgbdi7zMieM",
"title": "image.png",
"role": "image",
"mime": "image/png",
"mime": "image/jpg",
"position": 10,
"dataFileName": "Exporting as PDF_image.png"
"dataFileName": "Serving directly the conte.png"
},
{
"attachmentId": "xsGM34t8ssKV",
"attachmentId": "DsKDaFOcumH6",
"title": "image.png",
"role": "image",
"mime": "image/png",
"mime": "image/jpg",
"position": 10,
"dataFileName": "1_Exporting as PDF_image.png"
},
{
"attachmentId": "cvyes4f1Vhmm",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "2_Exporting as PDF_image.png"
"dataFileName": "1_Serving directly the conte.png"
}
]
}
@ -301,28 +597,89 @@
},
{
"isClone": false,
"noteId": "XUG1egT28FBk",
"noteId": "LTnkDnYmmZ7s",
"notePath": [
"OkOZllzB3fqN",
"XUG1egT28FBk"
"LTnkDnYmmZ7s"
],
"title": "Power users",
"notePosition": 50,
"title": "Scripting",
"notePosition": 110,
"prefix": null,
"isExpanded": true,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"attachments": [],
"dirFileName": "Power users",
"dirFileName": "Scripting",
"children": [
{
"isClone": false,
"noteId": "cTWlUHkiv1fB",
"notePath": [
"OkOZllzB3fqN",
"LTnkDnYmmZ7s",
"cTWlUHkiv1fB"
],
"title": "Examples",
"notePosition": 10,
"prefix": null,
"isExpanded": true,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"attachments": [],
"dirFileName": "Examples",
"children": [
{
"isClone": false,
"noteId": "g5Vta7jt3aq3",
"notePath": [
"OkOZllzB3fqN",
"LTnkDnYmmZ7s",
"cTWlUHkiv1fB",
"g5Vta7jt3aq3"
],
"title": "Downloading responses from Google Forms",
"notePosition": 10,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"dataFileName": "Downloading responses from Goo.html",
"attachments": []
}
]
}
]
},
{
"isClone": false,
"noteId": "m4Paddd5qnnQ",
"notePath": [
"OkOZllzB3fqN",
"m4Paddd5qnnQ"
],
"title": "Advanced usage",
"notePosition": 120,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"attachments": [],
"dirFileName": "Advanced usage",
"children": [
{
"isClone": false,
"noteId": "DtJJ20yEozPA",
"notePath": [
"OkOZllzB3fqN",
"XUG1egT28FBk",
"m4Paddd5qnnQ",
"DtJJ20yEozPA"
],
"title": "Theme development",
@ -349,7 +706,7 @@
"noteId": "5HH79ztN0fZA",
"notePath": [
"OkOZllzB3fqN",
"XUG1egT28FBk",
"m4Paddd5qnnQ",
"DtJJ20yEozPA",
"5HH79ztN0fZA"
],
@ -372,7 +729,7 @@
"dataFileName": "Creating a custom theme.html",
"attachments": [
{
"attachmentId": "bn93hwF7C8sR",
"attachmentId": "AJHVfQtIQgJ7",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -380,7 +737,7 @@
"dataFileName": "Creating a custom theme_im.png"
},
{
"attachmentId": "17p6z24yW5eP",
"attachmentId": "gXLyv5KXjfxg",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -388,7 +745,7 @@
"dataFileName": "1_Creating a custom theme_im.png"
},
{
"attachmentId": "gXLyv5KXjfxg",
"attachmentId": "on1gD7BzCWdN",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -396,7 +753,7 @@
"dataFileName": "2_Creating a custom theme_im.png"
},
{
"attachmentId": "AJHVfQtIQgJ7",
"attachmentId": "17p6z24yW5eP",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -404,7 +761,7 @@
"dataFileName": "3_Creating a custom theme_im.png"
},
{
"attachmentId": "on1gD7BzCWdN",
"attachmentId": "K3cdwj8f90m0",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -412,7 +769,7 @@
"dataFileName": "4_Creating a custom theme_im.png"
},
{
"attachmentId": "K3cdwj8f90m0",
"attachmentId": "bn93hwF7C8sR",
"title": "image.png",
"role": "image",
"mime": "image/png",
@ -426,11 +783,11 @@
"noteId": "aH8Dk5aMiq7R",
"notePath": [
"OkOZllzB3fqN",
"XUG1egT28FBk",
"m4Paddd5qnnQ",
"DtJJ20yEozPA",
"aH8Dk5aMiq7R"
],
"title": "Theme base (legacy vs. next)",
"title": "Customize the Next theme",
"notePosition": 20,
"prefix": null,
"isExpanded": false,
@ -438,23 +795,23 @@
"mime": "text/html",
"attributes": [],
"format": "html",
"dataFileName": "Theme base (legacy vs. next).html",
"dataFileName": "Customize the Next theme.html",
"attachments": [
{
"attachmentId": "u0zkXkD7rGXA",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "Theme base (legacy vs. nex.png"
},
{
"attachmentId": "5z4bC0x0eH0P",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "1_Theme base (legacy vs. nex.png"
"dataFileName": "Customize the Next theme_i.png"
},
{
"attachmentId": "u0zkXkD7rGXA",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "1_Customize the Next theme_i.png"
}
]
},
@ -463,7 +820,7 @@
"noteId": "pMq6N1oBV9oo",
"notePath": [
"OkOZllzB3fqN",
"XUG1egT28FBk",
"m4Paddd5qnnQ",
"DtJJ20yEozPA",
"pMq6N1oBV9oo"
],
@ -473,12 +830,160 @@
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
"attributes": [
{
"type": "relation",
"name": "internalLink",
"value": "po38jIc0LD2H",
"isInheritable": false,
"position": 10
}
],
"format": "html",
"dataFileName": "Reference.html",
"attachments": []
}
]
},
{
"isClone": false,
"noteId": "po38jIc0LD2H",
"notePath": [
"OkOZllzB3fqN",
"m4Paddd5qnnQ",
"po38jIc0LD2H"
],
"title": "Custom resource providers",
"notePosition": 20,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"dataFileName": "Custom resource providers.html",
"attachments": []
},
{
"isClone": false,
"noteId": "rGq9oI9hWwGf",
"notePath": [
"OkOZllzB3fqN",
"m4Paddd5qnnQ",
"rGq9oI9hWwGf"
],
"title": "REST API",
"notePosition": 30,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"attachments": [],
"dirFileName": "REST API",
"children": [
{
"isClone": false,
"noteId": "sztusxU10ADE",
"notePath": [
"OkOZllzB3fqN",
"m4Paddd5qnnQ",
"rGq9oI9hWwGf",
"sztusxU10ADE"
],
"title": "ETAPI",
"notePosition": 10,
"prefix": null,
"isExpanded": true,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"attachments": [],
"dirFileName": "ETAPI",
"children": [
{
"isClone": false,
"noteId": "f3xpgx6H01PW",
"notePath": [
"OkOZllzB3fqN",
"m4Paddd5qnnQ",
"rGq9oI9hWwGf",
"sztusxU10ADE",
"f3xpgx6H01PW"
],
"title": "API Reference",
"notePosition": 10,
"prefix": null,
"isExpanded": false,
"type": "webView",
"mime": "",
"attributes": [
{
"type": "label",
"name": "webViewSrc",
"value": "/etapi/docs",
"isInheritable": false,
"position": 10
}
],
"dataFileName": "API Reference.dat",
"attachments": []
}
]
},
{
"isClone": false,
"noteId": "9OiEC6pf3Wfv",
"notePath": [
"OkOZllzB3fqN",
"m4Paddd5qnnQ",
"rGq9oI9hWwGf",
"9OiEC6pf3Wfv"
],
"title": "Internal API",
"notePosition": 20,
"prefix": null,
"isExpanded": true,
"type": "text",
"mime": "text/html",
"attributes": [],
"format": "html",
"attachments": [],
"dirFileName": "Internal API",
"children": [
{
"isClone": false,
"noteId": "7uB5k0iCmOtZ",
"notePath": [
"OkOZllzB3fqN",
"m4Paddd5qnnQ",
"rGq9oI9hWwGf",
"9OiEC6pf3Wfv",
"7uB5k0iCmOtZ"
],
"title": "API Reference",
"notePosition": 10,
"prefix": null,
"isExpanded": false,
"type": "webView",
"mime": "",
"attributes": [
{
"type": "label",
"name": "webViewSrc",
"value": "/api/docs",
"isInheritable": false,
"position": 10
}
],
"dataFileName": "API Reference.dat",
"attachments": []
}
]
}
]
}
]
}

View File

@ -0,0 +1,56 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../style.css">
<base target="_parent">
<title data-trilium-title>Custom resource providers</title>
</head>
<body>
<div class="content">
<h1 data-trilium-h1>Custom resource providers</h1>
<div class="ck-content">
<p>A custom resource provider allows any file imported into Trilium (images,
fonts, stylesheets) to be publicly accessible via a URL.</p>
<p>A potential use case for this is to add embed a custom font alongside
a theme.</p>
<h2>Steps for creating a custom resource provider</h2>
<ol>
<li>Import a file such as an image or a font into Trilium by drag &amp; drop.</li>
<li>Select the file and go to the <i>Owned Attributes</i> section.</li>
<li>Add the label <code>#customResourceProvider=hello</code>.</li>
<li>To test if it is working, use a browser to navigate to <code>&lt;protocol&gt;://&lt;host&gt;/custom/hello</code> (where <code>&lt;protocol&gt;</code> is
either <code>http</code> or <code>https</code> based on your setup, and <code>&lt;host&gt;</code> is
the host or IP to your Trilium server instance). If you are running the
TriliumNext application without a server, use <code>http://localhost:37840</code> as
the base URL.</li>
<li>If everything went well, at the previous step the browser should have
downloaded the file uploaded in the first step.</li>
</ol>
<p>Instead of <code>hello</code>, the name can be:</p>
<ul>
<li>A path, such as <code>fonts/Roboto.ttf</code>, which would be accessible
via <code>&lt;host&gt;/custom/fonts/Roboto.ttf</code>.</li>
<li>As a more advanced use case, a regular expression to match multiple routes,
such as <code>hello/.*</code> which will be accessible via <code>/custom/hello/1</code>, <code>/custom/hello/2</code>, <code>/custom/hello/world</code>,
etc.</li>
</ul>
<h2>Using it in a theme</h2>
<p>For example, if you have a custom font to be imported by the theme, first
upload a font file into Trilium and assign it the <code>#customResourceProvider=fonts/myfont.ttf</code> attribute.</p>
<p>Then modify the theme CSS to point to:</p><pre><code class="language-text-css">@font-face {
font-family: customFont;
src: url("/custom/fonts/myfont.ttf");
}
div {
font-family: customFont;
}</code></pre>
</div>
</div>
</body>
</html>

View File

@ -19,7 +19,7 @@
keep them into one place.</p>
<p>As such, the first step is to create a new note to gather all the themes.</p>
<p>
<img src="Creating a custom theme_im.png" width="181" height="84">
<img src="5_Creating a custom theme_im.png" width="181" height="84">
</p>
<h2>Step 2. Create the theme</h2>
<figure class="table" style="width:100%;">
@ -32,7 +32,7 @@
<tr>
<td>
<figure class="image">
<img style="aspect-ratio:651/220;" src="1_Creating a custom theme_im.png"
<img style="aspect-ratio:651/220;" src="3_Creating a custom theme_im.png"
width="651" height="220">
</figure>
</td>
@ -42,7 +42,7 @@
<tr>
<td>
<figure class="image">
<img style="aspect-ratio:302/349;" src="2_Creating a custom theme_im.png"
<img style="aspect-ratio:302/349;" src="1_Creating a custom theme_im.png"
width="302" height="349">
</figure>
</td>
@ -51,7 +51,7 @@
<tr>
<td>
<figure class="image">
<img style="aspect-ratio:316/133;" src="3_Creating a custom theme_im.png"
<img style="aspect-ratio:316/133;" src="Creating a custom theme_im.png"
width="316" height="133">
</figure>
</td>
@ -72,15 +72,15 @@
<p>Refresh the application (Ctrl+Shift+R is a good way to do so) and go to
settings. You should see the newly created theme:</p>
<p>
<img src="4_Creating a custom theme_im.png" width="631" height="481">
<img src="2_Creating a custom theme_im.png" width="631" height="481">
</p>
<p>Afterwards the application will refresh itself with the new theme:</p>
<p>
<img src="5_Creating a custom theme_im.png" width="653" height="554">
<img src="4_Creating a custom theme_im.png" width="653" height="554">
</p>
<p>Do note that the theme will be based off of the legacy theme. To override
that and base the theme on the new TriliumNext theme, see:&nbsp;<a class="reference-link"
href="Theme%20base%20(legacy%20vs.%20next).html">Theme base (legacy vs. next)</a>
href="Customize%20the%20Next%20theme.html">Theme base (legacy vs. next)</a>
</p>
<h2>Step 5. Making changes</h2>
<p>Simply go back to the note and change according to needs. To apply the

View File

@ -5,20 +5,20 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../../style.css">
<base target="_parent">
<title data-trilium-title>Theme base (legacy vs. next)</title>
<title data-trilium-title>Customize the Next theme</title>
</head>
<body>
<div class="content">
<h1 data-trilium-h1>Theme base (legacy vs. next)</h1>
<h1 data-trilium-h1>Customize the Next theme</h1>
<div class="ck-content">
<p>By default, any custom theme will be based on the legacy light theme.
To change the TriliumNext theme instead, add the <code>#appThemeBase=next</code> attribute
To use the TriliumNext theme instead, add the <code>#appThemeBase=next</code> attribute
onto the existing theme. The <code>appTheme</code> attribute must also be
present.</p>
<p>
<img src="1_Theme base (legacy vs. nex.png" width="424" height="140">
<img src="Customize the Next theme_i.png" width="424" height="140">
</p>
<p>When <code>appThemeBase</code> is set to <code>next</code> it will use the
“TriliumNext (auto)” theme. Any other value is ignored and will use the

View File

@ -122,6 +122,11 @@ body.electron:not(.native-titlebar) {
height: 3px;
background-color: var(--workspace-tab-background-color);
}</code></pre>
<h2>Custom fonts</h2>
<p>Currently the only way to include a custom font is to use&nbsp;<a class="reference-link"
href="../Custom%20resource%20providers.html">Custom resource providers</a>.
Basically import a font into Trilium and assign it <code>#customResourceProvider=fonts/myfont.ttf</code> and
then import the font in CSS via <code>/custom/fonts/myfont.ttf</code>.</p>
</div>
</div>
</body>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -5,32 +5,35 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../style.css">
<base target="_parent">
<title data-trilium-title>Exporting as PDF</title>
<title data-trilium-title>Export as PDF</title>
</head>
<body>
<div class="content">
<h1 data-trilium-h1>Exporting as PDF</h1>
<h1 data-trilium-h1>Export as PDF</h1>
<div class="ck-content">
<figure class="image image-style-align-right image_resized" style="width:47.17%;">
<img style="aspect-ratio:951/432;" src="1_Exporting as PDF_image.png"
width="951" height="432">
<figure class="image image-style-align-right image_resized" style="width:50.63%;">
<img style="aspect-ratio:951/432;" src="Export as PDF_image.png" width="951"
height="432">
<figcaption>Screenshot of the note contextual menu indicating the “Export as PDF”
option.</figcaption>
</figure>
<p>On the desktop application of Trilium it is possible to export a note
as PDF. On the server or PWA (mobile), the option is not available due
to technical constraints and it will be hidden.</p>
<p>To print a note, select the
<img src="Exporting as PDF_image.png" width="29"
<img src="2_Export as PDF_image.png" width="29"
height="31">button to the right of the note and select <i>Export as PDF</i>.</p>
<p>Afterwards you will be prompted to select where to save the PDF file.
Upon confirmation, the resulting PDF will be opened automatically.</p>
Upon confirmation, the resulting PDF will be opened automatically using
the default/system application configured for PDFs.</p>
<p>Should you encounter any visual issues in the resulting PDF file (e.g.
a table does not fit properly, there is cut off text, etc.) feel free to
<a
href="#root/OeKBfN6JbMIq/jRV1MPt4mNSP/hrC6xn7hnDq5">report the issue</a>. In this case, it's best to offer a sample note (click
on the
<img src="Exporting as PDF_image.png" width="29" height="31">button, select Export note → This note and all of its descendants → HTML
<img src="2_Export as PDF_image.png" width="29" height="31">button, select Export note → This note and all of its descendants → HTML
in ZIP archive). Make sure not to accidentally leak any personal information.</p>
<h2>Landscape mode</h2>
<p>When exporting to PDF, there are no customizable settings such as page

View File

@ -0,0 +1,73 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../style.css">
<base target="_parent">
<title data-trilium-title>Zen mode</title>
</head>
<body>
<div class="content">
<h1 data-trilium-h1>Zen mode</h1>
<div class="ck-content">
<figure class="image image-style-align-center image_resized" style="width:62.15%;">
<img style="aspect-ratio:855/677;" src="5_Zen mode_image.png" width="855"
height="677">
<figcaption>Screenshot of Zen Mode activated on a Windows 11 system with native title
bar off and background effects on.</figcaption>
</figure>
<p>When Zen Mode is activated (pictured on the side), most of the user interface
of Trilium is hidden away in order to be able to focus on the content,
whether it's for reading or writing.</p>
<figure class="image image-style-align-right image_resized"
style="width:17.65%;">
<img style="aspect-ratio:265/386;" src="3_Zen mode_image.png" width="265"
height="386">
<figcaption>Screenshot of the Zen Mode option in the global menu.</figcaption>
</figure>
<h2>Activating &amp; deactivating</h2>
<p>The Zen Mode can be activated by accessing the global menu and selecting
the “Zen Mode” option:</p>
<p>Aside from the global menu, it's also possible to activate this mode by
using a keyboard shortcut which is Alt+Z by default. Look for <code>toggleZenMode</code> in
the shortcut configuration.</p>
<p>Once Zen Mode is activated, all the UI elements of the application will
be hidden away, including the global menu. In that case, the Zen Mode can
be deactivated either by pressing the
<img src="6_Zen mode_image.png" width="29"
height="31">icon in the top-right corner of the window or by pressing the keyboard
combination again.</p>
<p>Do note that, by design, activating or deactivating the Zen Mode applies
only to the current window. Restarting the application will also disable
the Zen Mode.</p>
<h2>Moving the window around</h2>
<p>If “Native title bar” is activated, then the operating system's default
title bar can be used to drag the window around. If deactivated, the window
can still be moved by dragging the mouse across the top part of the window
where the note titles are.</p>
<figure class="image image-style-align-left image_resized"
style="width:50%;">
<img style="aspect-ratio:1060/707;" src="7_Zen mode_image.png" width="1060"
height="707">
<figcaption>Screenshot of two notes side-by-side while Zen Mode is active, on Windows
11 with background effects off.</figcaption>
</figure>
<h2>Split windows and tabs</h2>
<p>Tabs are completely hidden, however it's still possible to use keyboard
shortcuts such as <code>firstTab</code> (Ctrl+1 by default), <code>secondTab</code> (Ctrl+2
by default). There are also some newer shortcuts such as <code>activateNextTab</code> (Ctrl+Tab)
or <code>activatePreviousTab</code> (Ctrl+Shift+Tab) that allow easy navigation,
however make sure that they are configured properly in the settings.</p>
<p>For the split view of notes, there are no keyboard shortcuts at the time
of writing, but it's still possible to have them in Zen Mode by creating
the split while the Zen Mode is off and then reactivating it afterwards.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View File

@ -0,0 +1,38 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../style.css">
<base target="_parent">
<title data-trilium-title>Installation</title>
</head>
<body>
<div class="content">
<h1 data-trilium-h1>Installation</h1>
<div class="ck-content">
<h2>Desktop application</h2>
<figure class="table">
<table style="border-color:transparent;border-style:solid;">
<tbody>
<tr>
<td style="border-color:transparent;text-align:center;">
<figure class="image image_resized" style="width:9.91%;">
<img style="aspect-ratio:267/267;" src="Installation_Fedora_logo.svg"
width="267" height="267">
</figure>
<p><a href="Installation/On%20Fedora%20Linux.html"><span class="text-big">Fedora</span></a>
</p>
</td>
</tr>
</tbody>
</table>
</figure>
<h2>Self-hosted server</h2>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -0,0 +1,82 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../style.css">
<base target="_parent">
<title data-trilium-title>On Fedora Linux</title>
</head>
<body>
<div class="content">
<h1 data-trilium-h1>On Fedora Linux</h1>
<div class="ck-content">
<p>First, download a release from GitHub.</p>
<figure class="table" style="width:100%;">
<table class="ck-table-resized">
<colgroup>
<col style="width:3.52%;">
<col style="width:58.5%;">
<col style="width:37.98%;">
</colgroup>
<tbody>
<tr>
<th>1</th>
<td>
<figure class="image">
<img style="aspect-ratio:816/581;" src="3_On Fedora Linux_Screenshot.png"
width="816" height="581">
</figure>
</td>
<td>In your file explorer, look for the <code>.rpm</code> file of TriliumNext.</td>
</tr>
<tr>
<th>2</th>
<td>
<figure class="image">
<img style="aspect-ratio:339/219;" src="On Fedora Linux_Screenshot.png"
width="339" height="219">
</figure>
</td>
<td>Right click the file and select <i>Open With Software Install</i>.</td>
</tr>
<tr>
<th>3</th>
<td>
<figure class="image">
<img style="aspect-ratio:996/953;" src="1_On Fedora Linux_Screenshot.png"
width="996" height="953">
</figure>
</td>
<td>
<p>GNOME Software will appear. Press the
<img src="2_On Fedora Linux_image.png"
width="106" height="34">.</p>
<p>You will be asked to confirm the action by entering your password.</p>
<p>After confirmation the software will start installing.</p>
<p>Once it's done the “Install” button will turn into
<img src="1_On Fedora Linux_image.png"
width="105" height="34">.</p>
</td>
</tr>
<tr>
<th>4</th>
<td>
<figure class="image">
<img style="aspect-ratio:389/224;" src="2_On Fedora Linux_Screenshot.png"
width="389" height="224">
</figure>
</td>
<td>After installation, the application will be available in the GNOME overview
section.</td>
</tr>
</tbody>
</table>
</figure>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0" width="267" height="267" id="svg2">
<defs id="defs5"/>
<path d="M 266.62575,133.50613 C 266.62575,59.98128 207.02222,0.37583 133.49792,0.37583 C 60.00668,0.37583 0.42639,59.93123 0.37425,133.41225 L 0.37425,236.4333 C 0.4138,253.11763 13.94545,266.62417 30.64027,266.62417 L 133.55192,266.62417 C 207.05167,266.59532 266.62575,207.01142 266.62575,133.50613" id="voice" style="fill:#294172"/>
<path d="M 77.126289,142.09756 C 77.126289,142.09756 124.97104,142.09756 124.97104,142.09756 C 124.97104,142.09756 124.97104,189.94234 124.97104,189.94234 C 124.97104,216.35263 103.53659,237.78707 77.126289,237.78707 C 50.715979,237.78707 29.28153,216.35263 29.28153,189.94234 C 29.28153,163.53203 50.715979,142.09756 77.126289,142.09756 z" id="in" style="fill:none;stroke:#3c6eb4;stroke-width:29.21"/>
<use transform="matrix(-1,0,0,-1,249.71151,284.2882)" id="finity" xlink:href="#in"/>
<path d="M 139.6074,127.52923 L 139.6074,189.87541 C 139.6074,224.37943 111.63203,252.35541 77.12679,252.35541 C 71.89185,252.35541 68.1703,251.7644 63.32444,250.49771 C 56.25849,248.64859 50.48398,242.85518 50.48158,236.1166 C 50.48158,227.97147 56.39394,222.0467 65.23187,222.0467 C 69.43824,222.0467 70.96454,222.85435 77.12679,222.85435 C 95.3184,222.85435 110.07443,208.11916 110.10634,189.92756 L 110.10634,161.27099 C 110.10634,158.70324 108.01971,156.62274 105.44767,156.62274 L 83.78246,156.61846 C 75.71034,156.61846 69.18845,150.18003 69.18845,142.0858 C 69.18414,133.94124 75.77725,127.52923 83.93653,127.52923" id="free" style="fill:#ffffff"/>
<use transform="matrix(-1,0,0,-1,249.71152,284.28821)" id="dom" xlink:href="#free"/>
<path d="M 243.65456,243.58425 C 243.65456,243.58425 243.6546,238.05286 243.6546,238.05286 L 241.12607,243.85062 C 241.12607,243.85062 238.66466,238.05286 238.66466,238.05286 L 238.66513,243.58425 L 237.24683,243.58425 L 237.24683,234.84933 L 238.73387,234.84933 C 238.73387,234.84933 241.16784,240.42984 241.16784,240.42984 L 243.56495,234.84933 L 245.07039,234.84933 L 245.07039,243.58425 L 243.65456,243.58425 z M 233.32154,236.31241 L 233.32154,243.58425 L 231.83941,243.58425 L 231.83941,236.31241 L 229.35453,236.31241 L 229.35453,234.84933 L 235.80399,234.84933 L 235.80399,236.31241" id="TM" style="fill:#3c6eb4"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -26,7 +26,7 @@
<th>1</th>
<td>
<figure class="image image_resized" style="width:100%;">
<img style="aspect-ratio:1256/1044;" src="Geo map_image.png" width="1256"
<img style="aspect-ratio:1256/1044;" src="10_Geo map_image.png" width="1256"
height="1044">
</figure>
</td>
@ -36,7 +36,7 @@
<th>2</th>
<td>
<figure class="image image_resized" style="width:100%;">
<img style="aspect-ratio:1720/1396;" src="1_Geo map_image.png" width="1720"
<img style="aspect-ratio:1720/1396;" src="3_Geo map_image.png" width="1720"
height="1396">
</figure>
</td>
@ -51,8 +51,8 @@
<li>Use the mouse wheel, two-finger gesture on a touchpad or the +/- buttons
on the top-left to adjust the zoom.</li>
</ul>
<p>The position on the map and the zoom are saved inside the map note. When
visting again the note it will restore this position.</p>
<p>The position on the map and the zoom are saved inside the map note and
restored when visiting again the note.</p>
<h2>Adding a marker using the map</h2>
<figure class="table" style="width:100%;">
<table class="ck-table-resized">
@ -69,18 +69,18 @@
<p>To create a marker, first navigate to the desired point on the map. Then
press the
<img class="image_resized" style="aspect-ratio:72/66;width:7.37%;"
src="2_Geo map_image.png" width="72" height="66">button on the top-right of the map.</p>
src="5_Geo map_image.png" width="72" height="66">button on the top-right of the map.</p>
<p>If the button is not visible, make sure the button section is visible
by pressing the chevron button (
<img class="image_resized" style="aspect-ratio:72/66;width:7.51%;"
src="3_Geo map_image.png" width="72" height="66">) in the top-right of the map.</p>
src="11_Geo map_image.png" width="72" height="66">) in the top-right of the map.</p>
</td>
</tr>
<tr>
<th>2</th>
<td>
<figure class="image image_resized" style="width:100%;">
<img style="aspect-ratio:1730/416;" src="4_Geo map_image.png" width="1730"
<img style="aspect-ratio:1730/416;" src="14_Geo map_image.png" width="1730"
height="416">
</figure>
<p>&nbsp;</p>
@ -96,7 +96,7 @@
<th>3</th>
<td>
<figure class="image">
<img style="aspect-ratio:1586/404;" src="5_Geo map_image.png" width="1586"
<img style="aspect-ratio:1586/404;" src="1_Geo map_image.png" width="1586"
height="404">
</figure>
<p>&nbsp;</p>
@ -107,7 +107,7 @@
<th>4</th>
<td>
<figure class="image">
<img style="aspect-ratio:1696/608;" src="6_Geo map_image.png" width="1696"
<img style="aspect-ratio:1696/608;" src="7_Geo map_image.png" width="1696"
height="608">
</figure>
<p>&nbsp;</p>
@ -118,6 +118,15 @@
</tbody>
</table>
</figure>
<h2>How the location of the markers is stored</h2>
<p>The location of a marker is stored in the <code>#geolocation</code> attribute
of the child notes:</p>
<figure class="image">
<img style="aspect-ratio:1288/278;" src="4_Geo map_image.png" width="1288"
height="278">
</figure>
<p>This value can be added manually if needed. The value of the attribute
is made up of the latitude and longitude separated by a comma.</p>
<h2>Repositioning markers</h2>
<p>It's possible to reposition existing markers by simply drag and dropping
them to the new destination.</p>
@ -125,13 +134,30 @@
<p>If moved by mistake, there is currently no way to undo the change. If
the mouse was not yet released, it's possible to force a refresh of the
page (Ctrl+R or Meta+R) to cancel it.</p>
<h2>Adding the geolocation manually</h2>
<p>The location of a marker is stored in the <code>#geolocation</code> attribute
of the child notes:</p>
<figure class="image">
<img style="aspect-ratio:1288/278;" src="7_Geo map_image.png" width="1288"
height="278">
</figure>
<h2>Interaction with the markers</h2>
<ul>
<li>Hovering over a marker will display the content of the note it belongs
to.
<ul>
<li>Clicking on the note title in the tooltip will navigate to the note in
the current view.</li>
</ul>
</li>
<li>Middle-clicking the marker will open the note in a new tab.</li>
<li>Right-clicking the marker will open a contextual menu allowing:
<ul>
<li>Opening the note in a new tab, split or window.</li>
<li>Opening the location using an external application (if the operating system
supports it).</li>
<li>Removing the marker from the map, which will remove the <code>#geolocation</code> attribute
of the note. To add it back again, the coordinates have to be manually
added back in.</li>
</ul>
</li>
</ul>
<h2>Adding the coordinates manually</h2>
<p>In a nutshell, create a child note and set the <code>#geolocation</code> attribute
to the coordinates.</p>
<p>The value of the attribute is made up of the latitude and longitude separated
by a comma.</p>
<h3>Adding from Google Maps</h3>
@ -142,7 +168,7 @@
<th>1</th>
<td>
<figure class="image image-style-align-center image_resized" style="width:100%;">
<img style="aspect-ratio:732/918;" src="8_Geo map_image.png" width="732"
<img style="aspect-ratio:732/918;" src="16_Geo map_image.png" width="732"
height="918">
</figure>
</td>
@ -159,7 +185,7 @@
<th>2</th>
<td>
<figure class="image image_resized" style="width:100%;">
<img style="aspect-ratio:518/84;" src="11_Geo map_image.png" width="518"
<img style="aspect-ratio:518/84;" src="19_Geo map_image.png" width="518"
height="84">
</figure>
</td>
@ -173,7 +199,7 @@
<th>3</th>
<td>
<figure class="image image_resized" style="width:100%;">
<img style="aspect-ratio:1074/276;" src="9_Geo map_image.png" width="1074"
<img style="aspect-ratio:1074/276;" src="12_Geo map_image.png" width="1074"
height="276">
</figure>
</td>
@ -199,7 +225,7 @@
<th>1</th>
<td>
<figure class="image image_resized" style="width:100%;">
<img style="aspect-ratio:562/454;" src="12_Geo map_image.png" width="562"
<img style="aspect-ratio:562/454;" src="17_Geo map_image.png" width="562"
height="454">
</figure>
</td>
@ -224,7 +250,7 @@
<th>3</th>
<td>
<figure class="image">
<img style="aspect-ratio:640/276;" src="14_Geo map_image.png" width="640"
<img style="aspect-ratio:640/276;" src="2_Geo map_image.png" width="640"
height="276">
</figure>
</td>
@ -249,7 +275,7 @@
<th>1</th>
<td>
<figure class="image">
<img style="aspect-ratio:226/74;" src="17_Geo map_image.png" width="226"
<img style="aspect-ratio:226/74;" src="8_Geo map_image.png" width="226"
height="74">
</figure>
</td>
@ -260,7 +286,7 @@
<th>2</th>
<td>
<figure class="image">
<img style="aspect-ratio:322/222;" src="18_Geo map_image.png" width="322"
<img style="aspect-ratio:322/222;" src="6_Geo map_image.png" width="322"
height="222">
</figure>
</td>
@ -271,7 +297,7 @@
<th>3</th>
<td>
<figure class="image image_resized" style="width:100%;">
<img style="aspect-ratio:620/530;" src="19_Geo map_image.png" width="620"
<img style="aspect-ratio:620/530;" src="15_Geo map_image.png" width="620"
height="530">
</figure>
</td>

View File

@ -0,0 +1,19 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../style.css">
<base target="_parent">
<title data-trilium-title>Mermaid Diagram</title>
</head>
<body>
<div class="content">
<h1 data-trilium-h1>Mermaid Diagram</h1>
<div class="ck-content"></div>
</div>
</body>
</html>

View File

@ -0,0 +1,19 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../../style.css">
<base target="_parent">
<title data-trilium-title>Downloading responses from Google Forms</title>
</head>
<body>
<div class="content">
<h1 data-trilium-h1>Downloading responses from Google Forms</h1>
<div class="ck-content"></div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,60 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../style.css">
<base target="_parent">
<title data-trilium-title>Serving directly the content of a note</title>
</head>
<body>
<div class="content">
<h1 data-trilium-h1>Serving directly the content of a note</h1>
<div class="ck-content">
<p>When accessing a shared note, Trilium will render it as a web page. Sometimes
it's desirable to serve the content directly so that it can be used in
a script or downloaded by the user.</p>
<figure class="table" style="width:100%;">
<table class="ck-table-resized">
<colgroup>
<col style="width:48.52%;">
<col style="width:51.48%;">
</colgroup>
<tbody>
<tr>
<td>
<figure class="image">
<img style="aspect-ratio:378/231;" src="Serving directly the conte.png"
width="378" height="231">
<figcaption>A note displayed as a web page (HTML)</figcaption>
</figure>
</td>
<td style="vertical-align:top;">
<figure class="image">
<img style="aspect-ratio:402/129;" src="1_Serving directly the conte.png"
width="402" height="129">
<figcaption>A note displayed as a raw format</figcaption>
</figure>
</td>
</tr>
</tbody>
</table>
</figure>
<h2>By adding an attribute to the note</h2>
<p>Simply add the <code>#shareRaw</code> attribute and the note will always
be rendered <i>raw</i> when accessed from the share URL.</p>
<h2>By altering the URL</h2>
<p>Append <code>?raw</code> to the URL to display a note in its raw format
regardless of whether the <code>#shareRaw</code> attribute is added on the
note.</p>
<p>
<img src="1_Serving directly the conte.png" width="402" height="129">
</p>
<p>&nbsp;</p>
</div>
</div>
</body>
</html>

View File

@ -6,6 +6,6 @@
</head>
<frameset cols="25%,75%">
<frame name="navigation" src="navigation.html">
<frame name="detail" src="User%20Guide/Types%20of%20notes/Geo%20map.html">
<frame name="detail" src="User%20Guide/Installation.html">
</frameset>
</html>

View File

@ -9,34 +9,82 @@
<ul>
<li>User Guide
<ul>
<li>Types of notes
<li><a href="User%20Guide/Installation.html" target="detail">Installation</a>
<ul>
<li><a href="User%20Guide/Types%20of%20notes/Geo%20map.html" target="detail">Geo map</a>
<li><a href="User%20Guide/Installation/On%20Fedora%20Linux.html" target="detail">On Fedora Linux</a>
</li>
</ul>
</li>
<li>Working with notes
<li>Features
<ul>
<li><a href="User%20Guide/Working%20with%20notes/Exporting%20as%20PDF.html"
target="detail">Exporting as PDF</a>
<li><a href="User%20Guide/Features/Export%20as%20PDF.html" target="detail">Export as PDF</a>
</li>
<li><a href="User%20Guide/Features/Zen%20mode.html" target="detail">Zen mode</a>
</li>
</ul>
</li>
<li>Power users
<li>Note Types
<ul>
<li><a href="User%20Guide/Note%20Types/Mermaid%20Diagram.html" target="detail">Mermaid Diagram</a>
</li>
<li><a href="User%20Guide/Note%20Types/Geo%20map.html" target="detail">Geo map</a>
</li>
</ul>
</li>
<li>Shared notes
<ul>
<li><a href="User%20Guide/Shared%20notes/Serving%20directly%20the%20content%20o.html"
target="detail">Serving directly the content of a note</a>
</li>
</ul>
</li>
<li>Scripting
<ul>
<li>Examples
<ul>
<li><a href="User%20Guide/Scripting/Examples/Downloading%20responses%20from%20Goo.html"
target="detail">Downloading responses from Google Forms</a>
</li>
</ul>
</li>
</ul>
</li>
<li>Advanced usage
<ul>
<li>Theme development
<ul>
<li><a href="User%20Guide/Power%20users/Theme%20development/Creating%20a%20custom%20theme.html"
<li><a href="User%20Guide/Advanced%20usage/Theme%20development/Creating%20a%20custom%20theme.html"
target="detail">Creating a custom theme</a>
</li>
<li><a href="User%20Guide/Power%20users/Theme%20development/Theme%20base%20(legacy%20vs.%20next).html"
target="detail">Theme base (legacy vs. next)</a>
<li><a href="User%20Guide/Advanced%20usage/Theme%20development/Customize%20the%20Next%20theme.html"
target="detail">Customize the Next theme</a>
</li>
<li><a href="User%20Guide/Power%20users/Theme%20development/Reference.html"
<li><a href="User%20Guide/Advanced%20usage/Theme%20development/Reference.html"
target="detail">Reference</a>
</li>
</ul>
</li>
<li><a href="User%20Guide/Advanced%20usage/Custom%20resource%20providers.html"
target="detail">Custom resource providers</a>
</li>
<li>REST API
<ul>
<li>ETAPI
<ul>
<li><a href="User%20Guide/Advanced%20usage/REST%20API/ETAPI/API%20Reference.dat"
target="detail">API Reference</a>
</li>
</ul>
</li>
<li>Internal API
<ul>
<li><a href="User%20Guide/Advanced%20usage/REST%20API/Internal%20API/API%20Reference.dat"
target="detail">API Reference</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>

View File

@ -1,6 +1,8 @@
import NoteContextAwareWidget from "../note_context_aware_widget.js";
import attributeService from "../../services/attributes.js";
import { t } from "../../services/i18n.js";
import type FNote from "../../entities/fnote.js";
import type { EventData } from "../../components/app_context.js";
const TPL = `
<div class="book-properties-widget">
@ -9,7 +11,7 @@ const TPL = `
padding: 12px 12px 6px 12px;
display: flex;
}
.book-properties-widget > * {
margin-right: 15px;
}
@ -17,19 +19,19 @@ const TPL = `
<div style="display: flex; align-items: baseline">
<span style="white-space: nowrap">${t("book_properties.view_type")}:&nbsp; &nbsp;</span>
<select class="view-type-select form-select form-select-sm">
<option value="grid">${t("book_properties.grid")}</option>
<option value="list">${t("book_properties.list")}</option>
</select>
</div>
<button type="button"
class="collapse-all-button btn btn-sm"
title="${t("book_properties.collapse_all_notes")}">
<span class="bx bx-layer-minus"></span>
${t("book_properties.collapse")}
</button>
@ -37,13 +39,18 @@ const TPL = `
class="expand-children-button btn btn-sm"
title="${t("book_properties.expand_all_children")}">
<span class="bx bx-move-vertical"></span>
${t("book_properties.expand")}
</button>
</div>
`;
export default class BookPropertiesWidget extends NoteContextAwareWidget {
private $viewTypeSelect!: JQuery<HTMLElement>;
private $expandChildrenButton!: JQuery<HTMLElement>;
private $collapseAllButton!: JQuery<HTMLElement>;
get name() {
return "bookProperties";
}
@ -70,11 +77,15 @@ export default class BookPropertiesWidget extends NoteContextAwareWidget {
this.contentSized();
this.$viewTypeSelect = this.$widget.find(".view-type-select");
this.$viewTypeSelect.on("change", () => this.toggleViewType(this.$viewTypeSelect.val()));
this.$viewTypeSelect.on("change", () => this.toggleViewType(String(this.$viewTypeSelect.val())));
this.$expandChildrenButton = this.$widget.find(".expand-children-button");
this.$expandChildrenButton.on("click", async () => {
if (!this.note.isLabelTruthy("expanded")) {
if (!this.noteId || !this.note) {
return;
}
if (!this.note?.isLabelTruthy("expanded")) {
await attributeService.addLabel(this.noteId, "expanded");
}
@ -83,6 +94,10 @@ export default class BookPropertiesWidget extends NoteContextAwareWidget {
this.$collapseAllButton = this.$widget.find(".collapse-all-button");
this.$collapseAllButton.on("click", async () => {
if (!this.noteId || !this.note) {
return;
}
// owned is important - we shouldn't remove inherited expanded labels
for (const expandedAttr of this.note.getOwnedLabels("expanded")) {
await attributeService.removeAttributeById(this.noteId, expandedAttr.attributeId);
@ -92,7 +107,11 @@ export default class BookPropertiesWidget extends NoteContextAwareWidget {
});
}
async refreshWithNote(note) {
async refreshWithNote(note: FNote) {
if (!this.note) {
return;
}
const viewType = this.note.getLabelValue("viewType") || "grid";
this.$viewTypeSelect.val(viewType);
@ -101,7 +120,11 @@ export default class BookPropertiesWidget extends NoteContextAwareWidget {
this.$collapseAllButton.toggle(viewType === "list");
}
async toggleViewType(type) {
async toggleViewType(type: string) {
if (!this.noteId) {
return;
}
if (type !== "list" && type !== "grid") {
throw new Error(t("book_properties.invalid_view_type", { type }));
}
@ -109,7 +132,7 @@ export default class BookPropertiesWidget extends NoteContextAwareWidget {
await attributeService.setLabel(this.noteId, "viewType", type);
}
entitiesReloadedEvent({ loadResults }) {
entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
if (loadResults.getAttributeRows().find((attr) => attr.noteId === this.noteId && attr.name === "viewType")) {
this.refresh();
}

View File

@ -231,7 +231,7 @@
"workspace_tab_background_color": "Culoare CSS ce va fi folosită în tab-urile ce aparțin spațiului de lucru",
"workspace_template": "Această notița va apărea în lista de șabloane când se crează o nouă notiță, dar doar când spațiul de lucru în care se află notița este focalizat",
"app_theme_base": "setați valoarea la „next” pentru a folosi drept temă de bază „TriliumNext” în loc de cea clasică.",
"print_landscape": "Schimbă orientarea paginii din portret în peisaj atunci când se exportă în PDF.",
"print_landscape": "Schimbă orientarea paginii din portret în vedere atunci când se exportă în PDF.",
"print_page_size": "Schimbă dimensiunea paginii când se exportă în PDF. Valori suportate: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>."
},
"attribute_editor": {

View File

@ -13,6 +13,7 @@ import appInfo from "../../services/app_info.js";
* url: https://github.com/TriliumNext/Notes/blob/v0.91.6/src/services/app_info.ts
* responses:
* '200':
* description: Installation info
* content:
* application/json:
* schema:

View File

@ -186,6 +186,51 @@ function setExpandedForSubtree(req: Request) {
};
}
/**
* @swagger
* /api/branches/{branchId}:
* delete:
* summary: Delete branch (note clone)
* operationId: branches-delete
* parameters:
* - name: branchId
* in: path
* required: true
* schema:
* $ref: "#/components/schemas/BranchId"
* - name: taskId
* in: query
* required: true
* schema:
* type: string
* description: Task group identifier
* - name: eraseNotes
* in: query
* schema:
* type: boolean
* required: false
* description: Whether to erase the note immediately
* - name: last
* in: query
* schema:
* type: boolean
* required: true
* description: Whether this is the last request of this task group
* responses:
* '200':
* description: Branch successfully deleted
* content:
* application/json:
* schema:
* type: object
* properties:
* noteDeleted:
* type: boolean
* description: Whether the last note clone was deleted
* security:
* - session: []
* tags: ["data"]
*/
function deleteBranch(req: Request) {
const last = req.query.last === "true";
const eraseNotes = req.query.eraseNotes === "true";

View File

@ -14,14 +14,85 @@ import type { Request } from "express";
import type BBranch from "../../becca/entities/bbranch.js";
import type { AttributeRow } from "../../becca/entities/rows.js";
/**
* @swagger
* /api/notes/{noteId}:
* get:
* summary: Retrieve note metadata
* operationId: notes-get
* parameters:
* - name: noteId
* in: path
* required: true
* schema:
* $ref: "#/components/schemas/NoteId"
* responses:
* '200':
* description: Note metadata
* content:
* application/json:
* schema:
* allOf:
* - $ref: '#/components/schemas/Note'
* - $ref: "#/components/schemas/Timestamps"
* security:
* - session: []
* tags: ["data"]
*/
function getNote(req: Request) {
return becca.getNoteOrThrow(req.params.noteId);
}
/**
* @swagger
* /api/notes/{noteId}/blob:
* get:
* summary: Retrieve note content
* operationId: notes-blob
* parameters:
* - name: noteId
* in: path
* required: true
* schema:
* $ref: "#/components/schemas/NoteId"
* responses:
* '304':
* description: Note content
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Blob'
* security:
* - session: []
* tags: ["data"]
*/
function getNoteBlob(req: Request) {
return blobService.getBlobPojo("notes", req.params.noteId);
}
/**
* @swagger
* /api/notes/{noteId}/metadata:
* get:
* summary: Retrieve note metadata (limited to timestamps)
* operationId: notes-metadata
* parameters:
* - name: noteId
* in: path
* required: true
* schema:
* $ref: "#/components/schemas/NoteId"
* responses:
* '200':
* description: Note metadata
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Timestamps"
* security:
* - session: []
* tags: ["data"]
*/
function getNoteMetadata(req: Request) {
const note = becca.getNoteOrThrow(req.params.noteId);
@ -62,6 +133,43 @@ function updateNoteData(req: Request) {
return noteService.updateNoteData(noteId, content, attachments);
}
/**
* @swagger
* /api/notes/{noteId}:
* delete:
* summary: Delete note
* operationId: notes-delete
* parameters:
* - name: noteId
* in: path
* required: true
* schema:
* $ref: "#/components/schemas/NoteId"
* - name: taskId
* in: query
* required: true
* schema:
* type: string
* description: Task group identifier
* - name: eraseNotes
* in: query
* schema:
* type: boolean
* required: false
* description: Whether to erase the note immediately
* - name: last
* in: query
* schema:
* type: boolean
* required: true
* description: Whether this is the last request of this task group
* responses:
* '200':
* description: Note successfully deleted
* security:
* - session: []
* tags: ["data"]
*/
function deleteNote(req: Request) {
const noteId = req.params.noteId;
const taskId = req.query.taskId;

File diff suppressed because one or more lines are too long

View File

@ -86,6 +86,58 @@ function forceFullSync() {
syncService.sync();
}
/**
* @swagger
* /api/sync/changed:
* get:
* summary: Pull sync changes
* operationId: sync-changed
* externalDocs:
* description: Server implementation
* url: https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/api/sync.ts
* parameters:
* - in: query
* name: instanceId
* required: true
* schema:
* type: string
* description: Local instance ID
* - in: query
* name: lastEntityChangeId
* required: true
* schema:
* type: integer
* description: Last locally present change ID
* - in: query
* name: logMarkerId
* required: true
* schema:
* type: string
* description: Marker to identify this request in server log
* responses:
* '200':
* description: Sync changes, limited to approximately one megabyte.
* content:
* application/json:
* schema:
* type: object
* properties:
* entityChanges:
* type: list
* items:
* $ref: '#/components/schemas/EntityChange'
* lastEntityChangeId:
* type: integer
* description: If `outstandingPullCount > 0`, pass this as parameter in your next request to continue.
* outstandingPullCount:
* type: int
* example: 42
* description: Number of changes not yet returned by the remote.
* security:
* - session: []
* tags:
* - sync
*/
function getChanged(req: Request) {
const startTime = Date.now();
@ -151,6 +203,60 @@ const partialRequests: Record<
}
> = {};
/**
* @swagger
* /api/sync/update:
* put:
* summary: Push sync changes
* description:
* "Basic usage: set `pageCount = 1`, `pageIndex = 0`, and omit `requestId`. Supply your entity changes in the request body."
* operationId: sync-update
* externalDocs:
* description: Server implementation
* url: https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/api/sync.ts
* parameters:
* - in: header
* name: pageCount
* required: true
* schema:
* type: integer
* - in: header
* name: pageIndex
* required: true
* schema:
* type: integer
* - in: header
* name: requestId
* schema:
* type: string
* description: ID to identify paginated requests
* - in: query
* name: logMarkerId
* required: true
* schema:
* type: string
* description: Marker to identify this request in server log
* requestBody:
* content:
* application/json:
* schema:
* type: object
* properties:
* instanceId:
* type: string
* description: Local instance ID
* entities:
* type: list
* items:
* $ref: '#/components/schemas/EntityChange'
* responses:
* '200':
* description: Changes processed successfully
* security:
* - session: []
* tags:
* - sync
*/
function update(req: Request) {
let { body } = req;

View File

@ -127,6 +127,46 @@ function getNotesAndBranchesAndAttributes(_noteIds: string[] | Set<string>) {
};
}
/**
* @swagger
* /api/tree:
* get:
* summary: Retrieve tree data
* operationId: tree
* externalDocs:
* description: Server implementation
* url: https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/api/tree.ts
* parameters:
* - in: query
* name: subTreeNoteId
* required: false
* schema:
* type: string
* description: Limit tree data to this note and descendants
* responses:
* '200':
* description: Notes, branches and attributes
* content:
* application/json:
* schema:
* type: object
* properties:
* branches:
* type: list
* items:
* $ref: '#/components/schemas/Branch'
* notes:
* type: list
* items:
* $ref: '#/components/schemas/Note'
* attributes:
* type: list
* items:
* $ref: '#/components/schemas/Attribute'
* security:
* - session: []
* tags: ["data"]
*/
function getTree(req: Request) {
const subTreeNoteId = typeof req.query.subTreeNoteId === "string" ? req.query.subTreeNoteId : "root";
const collectedNoteIds = new Set<string>([subTreeNoteId]);

View File

@ -1,4 +1,4 @@
import type { Router } from "express";
import type { Application, Router } from "express";
import swaggerUi from "swagger-ui-express";
import { readFile } from "fs/promises";
import { fileURLToPath } from "url";
@ -7,19 +7,29 @@ import yaml from "js-yaml";
import type { JsonObject } from "swagger-ui-express";
const __dirname = dirname(fileURLToPath(import.meta.url));
const swaggerDocument = yaml.load(
const etapiDocument = yaml.load(
await readFile(join(__dirname, "../etapi/etapi.openapi.yaml"), "utf8")
) as JsonObject;
const apiDocument = JSON.parse(await readFile(join(__dirname, "api", "openapi.json"), "utf-8"));
function register(router: Router) {
router.use(
"/etapi",
swaggerUi.serve,
swaggerUi.setup(swaggerDocument, {
function register(app: Application) {
app.use(
"/etapi/docs/",
swaggerUi.serveFiles(etapiDocument),
swaggerUi.setup(etapiDocument, {
explorer: true,
customSiteTitle: "TriliumNext ETAPI Documentation"
})
);
app.use(
"/api/docs/",
swaggerUi.serveFiles(apiDocument),
swaggerUi.setup(apiDocument, {
explorer: true,
customSiteTitle: "TriliumNext Internal API Documentation"
})
);
}
export default {

View File

@ -44,6 +44,15 @@ function parseNoteMeta(noteMeta: NoteMeta, docNameRoot: string): HiddenSubtreeIt
for (const attribute of noteMeta.attributes ?? []) {
if (attribute.name === "iconClass") {
iconClass = attribute.value;
continue;
}
if (attribute.name === "webViewSrc") {
item.attributes?.push({
type: "label",
name: attribute.name,
value: attribute.value
});
}
}
@ -64,6 +73,11 @@ function parseNoteMeta(noteMeta: NoteMeta, docNameRoot: string): HiddenSubtreeIt
});
}
// Handle web views
if (noteMeta.type === "webView") {
item.type = "webView";
}
// Handle children
if (noteMeta.children) {
const children: HiddenSubtreeItem[] = [];

View File

@ -1,3 +1,4 @@
import type { NoteType } from "../../becca/entities/rows.js";
import type AttachmentMeta from "./attachment_meta.js";
import type AttributeMeta from "./attribute_meta.js";
@ -15,7 +16,7 @@ export default interface NoteMeta {
notePosition?: number;
prefix?: string | null;
isExpanded?: boolean;
type?: string;
type?: NoteType;
mime?: string;
/** 'html' or 'markdown', applicable to text notes only */
format?: "html" | "markdown";

View File

@ -22,7 +22,7 @@ describe("Search", () => {
});
});
it.skip("simple path match", () => {
it("simple path match", () => {
rootNote.child(note("Europe").child(note("Austria")));
const searchContext = new SearchContext();
@ -32,7 +32,7 @@ describe("Search", () => {
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
});
it.skip("normal search looks also at attributes", () => {
it("normal search looks also at attributes", () => {
const austria = note("Austria");
const vienna = note("Vienna");
@ -50,7 +50,7 @@ describe("Search", () => {
expect(findNoteByTitle(searchResults, "Vienna")).toBeTruthy();
});
it.skip("normal search looks also at type and mime", () => {
it("normal search looks also at type and mime", () => {
rootNote.child(note("Effective Java", { type: "book", mime: "" })).child(note("Hello World.java", { type: "code", mime: "text/x-java" }));
const searchContext = new SearchContext();
@ -69,7 +69,7 @@ describe("Search", () => {
expect(searchResults.length).toEqual(2);
});
it.skip("only end leafs are results", () => {
it("only end leafs are results", () => {
rootNote.child(note("Europe").child(note("Austria")));
const searchContext = new SearchContext();
@ -79,7 +79,7 @@ describe("Search", () => {
expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy();
});
it.skip("only end leafs are results", () => {
it("only end leafs are results", () => {
rootNote.child(note("Europe").child(note("Austria").label("capital", "Vienna")));
const searchContext = new SearchContext();
@ -132,7 +132,7 @@ describe("Search", () => {
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
});
it.skip("inherited label comparison", () => {
it("inherited label comparison", () => {
rootNote.child(note("Europe").label("country", "", true).child(note("Austria")).child(note("Czech Republic")));
const searchContext = new SearchContext();
@ -527,7 +527,7 @@ describe("Search", () => {
expect(becca.notes[searchResults[0].noteId].title).toEqual("Europe");
});
it.skip("test note.text *=* something", () => {
it("test note.text *=* something", () => {
const italy = note("Italy").label("capital", "Rome");
const slovakia = note("Slovakia").label("capital", "Bratislava");
@ -540,7 +540,7 @@ describe("Search", () => {
expect(becca.notes[searchResults[0].noteId].title).toEqual("Slovakia");
});
it.skip("test that fulltext does not match archived notes", () => {
it("test that fulltext does not match archived notes", () => {
const italy = note("Italy").label("capital", "Rome");
const slovakia = note("Slovakia").label("capital", "Bratislava");