Merge remote-tracking branch 'origin/develop' into port/client_ts
							
								
								
									
										10
									
								
								.github/actions/build-electron/action.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -6,7 +6,7 @@ inputs: | |||||||
|     description: "The architecture to build for: x64, arm64" |     description: "The architecture to build for: x64, arm64" | ||||||
|     required: true |     required: true | ||||||
|   extension: |   extension: | ||||||
|     description: "Platform specific extensions to copy in the output: dmg, deb, rpm, exe" |     description: "Platform specific extensions to copy in the output: dmg, deb, rpm, exe, zip" | ||||||
|     required: true |     required: true | ||||||
| runs: | runs: | ||||||
|   using: composite |   using: composite | ||||||
| @@ -27,16 +27,12 @@ runs: | |||||||
|     - name: Install dependencies |     - name: Install dependencies | ||||||
|       shell: bash |       shell: bash | ||||||
|       run: npm ci |       run: npm ci | ||||||
|     - name: Temporary Flatpak arm64 workaround till https://github.com/electron/forge/pull/3839 is merged |  | ||||||
|       if: ${{ inputs.os == 'linux' && inputs.arch == 'arm64' }} |  | ||||||
|       shell: bash |  | ||||||
|       run:  sed -e "s/case 'armv7l'/case 'arm64'/g" -e "s/return 'arm'/return 'aarch64'/g" -i node_modules/@electron-forge/maker-flatpak/dist/MakerFlatpak.js |  | ||||||
|     - name: Update build info |     - name: Update build info | ||||||
|       shell: bash |       shell: bash | ||||||
|       run: npm run update-build-info |       run: npm run chore:update-build-info | ||||||
|     - name: Run electron-forge |     - name: Run electron-forge | ||||||
|       shell: bash |       shell: bash | ||||||
|       run: npm run make-electron -- --arch=${{ inputs.arch }} |       run: npm run electron-forge:make -- --arch=${{ inputs.arch }} | ||||||
|     - name: Prepare artifacts |     - name: Prepare artifacts | ||||||
|       shell: bash |       shell: bash | ||||||
|       run: | |       run: | | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								.github/actions/build-server/action.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,4 +1,7 @@ | |||||||
| inputs: | inputs: | ||||||
|  |   os: | ||||||
|  |     description: "One of the supported platforms: windows" | ||||||
|  |     required: true | ||||||
|   arch: |   arch: | ||||||
|     description: "The architecture to build for: x64, arm64" |     description: "The architecture to build for: x64, arm64" | ||||||
|     required: true |     required: true | ||||||
| @@ -18,7 +21,7 @@ runs: | |||||||
|         MATRIX_ARCH: ${{ inputs.arch }} |         MATRIX_ARCH: ${{ inputs.arch }} | ||||||
|       shell: bash |       shell: bash | ||||||
|       run: | |       run: | | ||||||
|         npm run update-build-info |         npm run chore:update-build-info | ||||||
|         ./bin/build-server.sh |         ./bin/build-server.sh | ||||||
|     - name: Prepare artifacts |     - name: Prepare artifacts | ||||||
|       shell: bash |       shell: bash | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								.github/workflows/main-docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -100,7 +100,20 @@ jobs: | |||||||
|  |  | ||||||
|   build: |   build: | ||||||
|     name: Build Docker images |     name: Build Docker images | ||||||
|     runs-on: ubuntu-latest |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|  |       matrix: | ||||||
|  |         include: | ||||||
|  |           - dockerfile: Dockerfile.alpine | ||||||
|  |             platform: linux/amd64 | ||||||
|  |             image: ubuntu-latest | ||||||
|  |           - dockerfile: Dockerfile | ||||||
|  |             platform: linux/arm64 | ||||||
|  |             image: ubuntu-24.04-arm | ||||||
|  |           - dockerfile: Dockerfile | ||||||
|  |             platform: linux/arm/v7 | ||||||
|  |             image: ubuntu-24.04-arm | ||||||
|  |     runs-on: ${{ matrix.image }} | ||||||
|     needs: |     needs: | ||||||
|       - test_docker |       - test_docker | ||||||
|     permissions: |     permissions: | ||||||
| @@ -108,16 +121,6 @@ jobs: | |||||||
|       packages: write |       packages: write | ||||||
|       attestations: write |       attestations: write | ||||||
|       id-token: write |       id-token: write | ||||||
|     strategy: |  | ||||||
|       fail-fast: false |  | ||||||
|       matrix: |  | ||||||
|         include: |  | ||||||
|           - dockerfile: Dockerfile.alpine |  | ||||||
|             platform: linux/amd64 |  | ||||||
|           - dockerfile: Dockerfile |  | ||||||
|             platform: linux/arm64 |  | ||||||
|           - dockerfile: Dockerfile |  | ||||||
|             platform: linux/arm/v7 |  | ||||||
|     steps: |     steps: | ||||||
|       - name: Prepare |       - name: Prepare | ||||||
|         run: | |         run: | | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								.github/workflows/main.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -29,7 +29,7 @@ jobs: | |||||||
|             extension: [deb, rpm, zip, flatpak] |             extension: [deb, rpm, zip, flatpak] | ||||||
|           - name: windows |           - name: windows | ||||||
|             image: windows-latest |             image: windows-latest | ||||||
|             extension: exe |             extension: [exe, zip] | ||||||
|     runs-on: ${{ matrix.os.image }} |     runs-on: ${{ matrix.os.image }} | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v4 |       - uses: actions/checkout@v4 | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								.github/workflows/nightly.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -26,7 +26,7 @@ jobs: | |||||||
|             extension: [deb, rpm, zip, flatpak] |             extension: [deb, rpm, zip, flatpak] | ||||||
|           - name: windows |           - name: windows | ||||||
|             image: windows-latest |             image: windows-latest | ||||||
|             extension: exe |             extension: [exe, zip] | ||||||
|     runs-on: ${{ matrix.os.image }} |     runs-on: ${{ matrix.os.image }} | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v4 |       - uses: actions/checkout@v4 | ||||||
| @@ -38,7 +38,7 @@ jobs: | |||||||
|         shell: bash |         shell: bash | ||||||
|         run: npm ci |         run: npm ci | ||||||
|       - name: Update nightly version |       - name: Update nightly version | ||||||
|         run: npm run ci-update-nightly-version |         run: npm run chore:ci-update-nightly-version | ||||||
|       - name: Run the build |       - name: Run the build | ||||||
|         uses: ./.github/actions/build-electron |         uses: ./.github/actions/build-electron | ||||||
|         with: |         with: | ||||||
| @@ -75,6 +75,7 @@ jobs: | |||||||
|       - name: Run the build |       - name: Run the build | ||||||
|         uses: ./.github/actions/build-server |         uses: ./.github/actions/build-server | ||||||
|         with: |         with: | ||||||
|  |           os: linux | ||||||
|           arch: ${{ matrix.arch }} |           arch: ${{ matrix.arch }} | ||||||
|  |  | ||||||
|       - name: Publish release |       - name: Publish release | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -26,7 +26,7 @@ jobs: | |||||||
|             extension: [deb, rpm, zip, flatpak] |             extension: [deb, rpm, zip, flatpak] | ||||||
|           - name: windows |           - name: windows | ||||||
|             image: windows-latest |             image: windows-latest | ||||||
|             extension: exe |             extension: [exe, zip] | ||||||
|     runs-on: ${{ matrix.os.image }} |     runs-on: ${{ matrix.os.image }} | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v4 |       - uses: actions/checkout@v4 | ||||||
| @@ -65,6 +65,7 @@ jobs: | |||||||
|       - name: Run the build |       - name: Run the build | ||||||
|         uses: ./.github/actions/build-server |         uses: ./.github/actions/build-server | ||||||
|         with: |         with: | ||||||
|  |           os: linux | ||||||
|           arch: ${{ matrix.arch }} |           arch: ${{ matrix.arch }} | ||||||
|  |  | ||||||
|       - name: Publish release |       - name: Publish release | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ image: | |||||||
| tasks: | tasks: | ||||||
|     - before: nvm install 20.15.1 && nvm use 20.15.1 |     - before: nvm install 20.15.1 && nvm use 20.15.1 | ||||||
|       init: npm install |       init: npm install | ||||||
|       command: npm run start-server |       command: npm run server:start | ||||||
|  |  | ||||||
| ports: | ports: | ||||||
|     - port: 8080 |     - port: 8080 | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -5,8 +5,8 @@ | |||||||
|     { |     { | ||||||
|       "console": "integratedTerminal", |       "console": "integratedTerminal", | ||||||
|       "internalConsoleOptions": "neverOpen", |       "internalConsoleOptions": "neverOpen", | ||||||
|       "name": "nodemon start-server", |       "name": "nodemon server:start", | ||||||
|       "program": "${workspaceFolder}/src/www", |       "program": "${workspaceFolder}/src/main", | ||||||
|       "request": "launch", |       "request": "launch", | ||||||
|       "restart": true, |       "restart": true, | ||||||
|       "runtimeExecutable": "nodemon", |       "runtimeExecutable": "nodemon", | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -18,5 +18,6 @@ | |||||||
|   "github-actions.workflows.pinned.workflows": [".github/workflows/nightly.yml"], |   "github-actions.workflows.pinned.workflows": [".github/workflows/nightly.yml"], | ||||||
|   "[css]": { |   "[css]": { | ||||||
|     "editor.defaultFormatter": "vscode.css-language-features" |     "editor.defaultFormatter": "vscode.css-language-features" | ||||||
|   } |   }, | ||||||
|  |   "npm.exclude": ["**/build", "**/dist", "**/out/**"] | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| # Build stage | # 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 | # Configure build dependencies in a single layer | ||||||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | RUN apt-get update && apt-get install -y --no-install-recommends \ | ||||||
| @@ -25,7 +25,7 @@ RUN cp -R build/src/* src/. && \ | |||||||
|     cp build/docker_healthcheck.js . && \     |     cp build/docker_healthcheck.js . && \     | ||||||
|     rm docker_healthcheck.ts && \ |     rm docker_healthcheck.ts && \ | ||||||
|     npm install && \ |     npm install && \ | ||||||
|     npm run webpack && \ |     npm run build:webpack && \ | ||||||
|     npm prune --omit=dev && \ |     npm prune --omit=dev && \ | ||||||
|     npm cache clean --force && \ |     npm cache clean --force && \ | ||||||
|     cp -r src/public/app/doc_notes src/public/app-dist/. && \ |     cp -r src/public/app/doc_notes src/public/app-dist/. && \ | ||||||
| @@ -36,7 +36,7 @@ RUN cp -R build/src/* src/. && \ | |||||||
|     rm -r build |     rm -r build | ||||||
|  |  | ||||||
| # Runtime stage | # Runtime stage | ||||||
| FROM node:22.13.1-bullseye-slim | FROM node:22.14.0-bullseye-slim | ||||||
|  |  | ||||||
| # Install only runtime dependencies | # Install only runtime dependencies | ||||||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | RUN apt-get update && apt-get install -y --no-install-recommends \ | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| # Build stage | # Build stage | ||||||
| FROM node:22.13.1-alpine AS builder | FROM node:22.14.0-alpine AS builder | ||||||
|  |  | ||||||
| # Configure build dependencies | # Configure build dependencies | ||||||
| RUN apk add --no-cache --virtual .build-dependencies \ | RUN apk add --no-cache --virtual .build-dependencies \ | ||||||
| @@ -24,7 +24,7 @@ RUN cp -R build/src/* src/. && \ | |||||||
|     cp build/docker_healthcheck.js . && \ |     cp build/docker_healthcheck.js . && \ | ||||||
|     rm docker_healthcheck.ts && \ |     rm docker_healthcheck.ts && \ | ||||||
|     npm install && \ |     npm install && \ | ||||||
|     npm run webpack && \ |     npm run build:webpack && \ | ||||||
|     npm prune --omit=dev && \ |     npm prune --omit=dev && \ | ||||||
|     npm cache clean --force && \ |     npm cache clean --force && \ | ||||||
|     cp -r src/public/app/doc_notes src/public/app-dist/. && \ |     cp -r src/public/app/doc_notes src/public/app-dist/. && \ | ||||||
| @@ -35,7 +35,7 @@ RUN cp -R build/src/* src/. && \ | |||||||
|     rm -r build |     rm -r build | ||||||
|  |  | ||||||
| # Runtime stage | # Runtime stage | ||||||
| FROM node:22.13.1-alpine | FROM node:22.14.0-alpine | ||||||
|  |  | ||||||
| # Install runtime dependencies | # Install runtime dependencies | ||||||
| RUN apk add --no-cache su-exec shadow | RUN apk add --no-cache su-exec shadow | ||||||
|   | |||||||
| @@ -78,7 +78,7 @@ Trilium 也提供 Flatpak: | |||||||
|  |  | ||||||
| ```shell | ```shell | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## 👏 致谢 | ## 👏 致谢 | ||||||
|   | |||||||
| @@ -86,7 +86,7 @@ Clone localmente y ejecute | |||||||
|  |  | ||||||
| ```shell | ```shell | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## 👏 Reconocimientos | ## 👏 Reconocimientos | ||||||
|   | |||||||
| @@ -73,7 +73,7 @@ Clona localmente ed esegui | |||||||
|  |  | ||||||
| ```shell | ```shell | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## 👏 Riconoscimenti | ## 👏 Riconoscimenti | ||||||
|   | |||||||
| @@ -54,7 +54,7 @@ Trilium は Flatpak としても提供されます: | |||||||
|  |  | ||||||
| ```shell | ```shell | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## 📢 シャウトアウト | ## 📢 シャウトアウト | ||||||
|   | |||||||
| @@ -102,7 +102,7 @@ You can also read [Patterns of personal knowledge base](https://triliumnext.gith | |||||||
| git clone https://github.com/TriliumNext/Notes.git | git clone https://github.com/TriliumNext/Notes.git | ||||||
| cd Notes | cd Notes | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Documentation | ### Documentation | ||||||
|   | |||||||
| @@ -44,7 +44,7 @@ Trilium предоставляется в виде десктопного при | |||||||
|  |  | ||||||
| ```shell | ```shell | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## 👏 Благодарности | ## 👏 Благодарности | ||||||
|   | |||||||
| @@ -7,9 +7,9 @@ const DEST_DIR_NODE_MODULES = path.join(DEST_DIR, "node_modules"); | |||||||
|  |  | ||||||
| const VERBOSE = process.env.VERBOSE; | const VERBOSE = process.env.VERBOSE; | ||||||
|  |  | ||||||
| function log(...args) { | function log(...args: any[]) { | ||||||
|     if (VERBOSE) { |     if (VERBOSE) { | ||||||
|         console.log(args); |         console.log(...args); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -29,7 +29,12 @@ const copy = async () => { | |||||||
|         fs.copySync(path.join("build", srcFile), destFile, { recursive: true }); |         fs.copySync(path.join("build", srcFile), destFile, { recursive: true }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const filesToCopy = ["config-sample.ini", "tsconfig.webpack.json"]; |     const filesToCopy = [ | ||||||
|  |         "config-sample.ini", | ||||||
|  |         "tsconfig.webpack.json", | ||||||
|  |         "./src/etapi/etapi.openapi.yaml", | ||||||
|  |         "./src/routes/api/openapi.json" | ||||||
|  |     ]; | ||||||
|     for (const file of filesToCopy) { |     for (const file of filesToCopy) { | ||||||
|         log(`Copying ${file}`); |         log(`Copying ${file}`); | ||||||
|         await fs.copy(file, path.join(DEST_DIR, file)); |         await fs.copy(file, path.join(DEST_DIR, file)); | ||||||
| @@ -90,7 +95,6 @@ const copy = async () => { | |||||||
|         "node_modules/mark.js/dist/", |         "node_modules/mark.js/dist/", | ||||||
|         "node_modules/normalize.css/", |         "node_modules/normalize.css/", | ||||||
|         "node_modules/jquery.fancytree/dist/", |         "node_modules/jquery.fancytree/dist/", | ||||||
|         "node_modules/bootstrap/dist/", |  | ||||||
|         "node_modules/autocomplete.js/dist/", |         "node_modules/autocomplete.js/dist/", | ||||||
|         "node_modules/codemirror/lib/", |         "node_modules/codemirror/lib/", | ||||||
|         "node_modules/codemirror/addon/", |         "node_modules/codemirror/addon/", | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ rm -rf "$DIR" | |||||||
| mkdir -pv "$DIR" | mkdir -pv "$DIR" | ||||||
|  |  | ||||||
| echo Webpack start | echo Webpack start | ||||||
| npm run webpack | npm run build:webpack | ||||||
| echo Webpack finish | echo Webpack finish | ||||||
|  |  | ||||||
| echo "Copying Trilium to build directory $DIR" | echo "Copying Trilium to build directory $DIR" | ||||||
|   | |||||||
							
								
								
									
										189
									
								
								bin/generate-openapi.ts
									
									
									
									
									
										Normal 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 | ||||||
|  |  */ | ||||||
| @@ -1,7 +1,5 @@ | |||||||
| #!/usr/bin/env bash | #!/usr/bin/env bash | ||||||
|  |  | ||||||
| export GITHUB_REPO=trilium |  | ||||||
|  |  | ||||||
| if [[ $# -eq 0 ]] ; then | if [[ $# -eq 0 ]] ; then | ||||||
|     echo "Missing argument of new version" |     echo "Missing argument of new version" | ||||||
|     exit 1 |     exit 1 | ||||||
| @@ -32,7 +30,7 @@ mv package.json.tmp package.json | |||||||
|  |  | ||||||
| git add package.json | git add package.json | ||||||
|  |  | ||||||
| npm run update-build-info | npm run chore:update-build-info | ||||||
|  |  | ||||||
| git add src/services/build.ts | git add src/services/build.ts | ||||||
|  |  | ||||||
| @@ -40,10 +38,18 @@ TAG=v$VERSION | |||||||
|  |  | ||||||
| echo "Committing package.json version change" | echo "Committing package.json version change" | ||||||
|  |  | ||||||
| git commit -m "release $VERSION" | git commit -m "chore(release): $VERSION" | ||||||
| git push | git push | ||||||
|  |  | ||||||
| echo "Tagging commit with $TAG" | echo "Tagging commit with $TAG" | ||||||
|  |  | ||||||
| git tag $TAG | git tag $TAG | ||||||
| git push origin $TAG | git push origin $TAG | ||||||
|  |  | ||||||
|  | echo "Updating master" | ||||||
|  |  | ||||||
|  | git fetch | ||||||
|  | git checkout master | ||||||
|  | git reset --hard origin/master | ||||||
|  | git merge origin/develop | ||||||
|  | git push | ||||||
| @@ -30,13 +30,19 @@ trustedReverseProxy=false | |||||||
|  |  | ||||||
|  |  | ||||||
| [Session] | [Session] | ||||||
| # Use this setting to constrain the current instance's "Path" value for the set cookies | # Use this setting to set a custom value for the "Path" Attribute value of the session cookie. | ||||||
| # This can be useful, when you have several instances running on the same domain, under different paths (e.g. by using a reverse proxy). | # This can be useful, when you have several instances running on the same domain, under different paths (e.g. by using a reverse proxy). | ||||||
| # It prevents your instances from overwriting each others' cookies. | # It prevents your instances from overwriting each others' cookies, allowing you to stay logged in multiple instances simultanteously. | ||||||
| # e.g. if you have https://your-domain.com/triliumNext/instanceA and https://your-domain.com/triliumNext/instanceB | # E.g. if you have instances running under https://your-domain.com/triliumNext/instanceA and https://your-domain.com/triliumNext/instanceB | ||||||
| # you would want to set the cookiePath value to "/triliumNext/instanceA" for your first and "/triliumNext/instanceB" for your second instance | # you would want to set the cookiePath value to "/triliumNext/instanceA" for your first and "/triliumNext/instanceB" for your second instance | ||||||
| cookiePath=/ | cookiePath=/ | ||||||
|  |  | ||||||
|  | # Use this setting to set a custom value for the "Max-Age" Attribute of the session cookie. | ||||||
|  | # This controls how long your session will be valid, before it expires and you need to log in again, when you use the "Remember Me" option. | ||||||
|  | # Value needs to be entered in Seconds. | ||||||
|  | # Default value is 1814400 Seconds, which is 21 Days. | ||||||
|  | cookieMaxAge=1814400 | ||||||
|  |  | ||||||
| [Sync] | [Sync] | ||||||
| #syncServerHost= | #syncServerHost= | ||||||
| #syncServerTimeout= | #syncServerTimeout= | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								db/migrations/0229__tasks.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,10 @@ | |||||||
|  | CREATE TABLE IF NOT EXISTS "tasks" | ||||||
|  | ( | ||||||
|  | 	"taskId"	TEXT NOT NULL PRIMARY KEY, | ||||||
|  | 	"parentNoteId"	TEXT NOT NULL, | ||||||
|  | 	"title"	TEXT NOT NULL DEFAULT "", | ||||||
|  | 	"dueDate"	INTEGER, | ||||||
|  | 	"isDone"	INTEGER NOT NULL DEFAULT 0, | ||||||
|  | 	"isDeleted"	INTEGER NOT NULL DEFAULT 0, | ||||||
|  | 	"utcDateModified"	TEXT NOT NULL | ||||||
|  | ); | ||||||
| @@ -132,3 +132,14 @@ CREATE INDEX IDX_attachments_ownerId_role | |||||||
| CREATE INDEX IDX_notes_blobId on notes (blobId); | CREATE INDEX IDX_notes_blobId on notes (blobId); | ||||||
| CREATE INDEX IDX_revisions_blobId on revisions (blobId); | CREATE INDEX IDX_revisions_blobId on revisions (blobId); | ||||||
| CREATE INDEX IDX_attachments_blobId on attachments (blobId); | CREATE INDEX IDX_attachments_blobId on attachments (blobId); | ||||||
|  |  | ||||||
|  | CREATE TABLE IF NOT EXISTS "tasks" | ||||||
|  | ( | ||||||
|  | 	"taskId"	TEXT NOT NULL PRIMARY KEY, | ||||||
|  | 	"parentNoteId"	TEXT NOT NULL, | ||||||
|  | 	"title"	TEXT NOT NULL DEFAULT "", | ||||||
|  | 	"dueDate"	INTEGER, | ||||||
|  | 	"isDone"	INTEGER NOT NULL DEFAULT 0, | ||||||
|  | 	"isDeleted"	INTEGER NOT NULL DEFAULT 0, | ||||||
|  | 	"utcDateModified"	TEXT NOT NULL | ||||||
|  | ); | ||||||
| @@ -38,12 +38,12 @@ | |||||||
|  |  | ||||||
|          |          | ||||||
|             <div id="content" class="type-text ck-content"> |             <div id="content" class="type-text ck-content"> | ||||||
|                 <h3>The native node bindings</h3><p><code>better-sqlite3</code> has native Node bindings. With updates of <code>better-sqlite3</code>, but also of Electron and Node.js versions, these bindings need to be updated.</p><p>Note that Electron and Node.js versions need different versions of these bindings, since Electron usually packs a different version of Node.js.</p><p>During development, <code>npm install</code> tries to build or reuse prebuilt natives for the current Node.js version. This makes <code>npm run start-server</code> work out of the box. Trying to run <code>npm run start-electron</code> with these versions generally causes an error such as this:</p><pre><code class="language-text-plain">Uncaught Exception: |                 <h3>The native node bindings</h3><p><code>better-sqlite3</code> has native Node bindings. With updates of <code>better-sqlite3</code>, but also of Electron and Node.js versions, these bindings need to be updated.</p><p>Note that Electron and Node.js versions need different versions of these bindings, since Electron usually packs a different version of Node.js.</p><p>During development, <code>npm install</code> tries to build or reuse prebuilt natives for the current Node.js version. This makes <code>npm run server:start</code> work out of the box. Trying to run <code>npm run electron:start</code> with these versions generally causes an error such as this:</p><pre><code class="language-text-plain">Uncaught Exception: | ||||||
| Error: The module '/Users/elian/Projects/Notes/node_modules/better-sqlite3/build/Release/better_sqlite3.node' | Error: The module '/Users/elian/Projects/Notes/node_modules/better-sqlite3/build/Release/better_sqlite3.node' | ||||||
| was compiled against a different Node.js version using | was compiled against a different Node.js version using | ||||||
| NODE_MODULE_VERSION 108. This version of Node.js requires | NODE_MODULE_VERSION 108. This version of Node.js requires | ||||||
| NODE_MODULE_VERSION 116. Please try re-compiling or re-installing | NODE_MODULE_VERSION 116. Please try re-compiling or re-installing | ||||||
| the module (for instance, using `npm rebuild` or `npm install`).</code></pre><h3>How the natives are handled</h3><p>Locally, this can be fixed by rebuilding the binaries, which is what <code>npm run switch-electron</code> does, which uses <code>electron-rebuild</code> under the hood.</p><p>When the deliveries are built (see <a class="reference-link type-text" href="UTB518X6X9Uh.html">Build deliveries locally</a>), it is not feasible to rebuild the dependencies since we are building for multiple platforms. Luckily, <code>better-sqlite3</code> provides these prebuilt binaries from us, available as artifacts on <a href="https://github.com/WiseLibs/better-sqlite3/releases/">their GitHub releases page</a>. </p><p>The build script manages the natives for <code>better-sqlite3</code> by keeping a copy of the <code>.node</code> file for every platform in <code>bin/better-sqlite3</code>.</p><p>Whenever the version of <code>better-sqlite3</code> changes, the <code>.node</code> files must also be renewed based on their releases page. To simplify this process, a script was created in <code>bin/better-sqlite3/update.sh</code>.</p><h2>How to update the natives</h2><p>The update script needs to know the version of Electron or Node.js for which to download the prebuilt binaries.</p><p>If you get errors during download, check on the <a href="https://github.com/WiseLibs/better-sqlite3/releases/">releases page</a> to ensure that this particular combination of Electron/Node actually exists for the given release.</p><p>To determine the <code>NODE_MODULE_VERSION</code> that is required, look for <code>This version of Node.js requires</code><br><code>NODE_MODULE_VERSION</code> in the error when starting Trilium via:</p><ul><li><code>npm run start-electron</code> (or run any Electron <a href="UTB518X6X9Uh.html" class="type-text">delivery</a>), case in which the <span style="color:#c0bfbc;"><code>ELECTRON_VERSION</code> variable needs to be changed.</span></li><li><span style="color:#c0bfbc;"><code>npm run start-server</code></span> (or run the Linux server delivery), case in which the <code>NODE_VERSION</code> variable needs to be changed.</li></ul><p>Check which files got changed after running the update script and for each platform that got changed, test it locally via <a class="reference-link type-text" href="UTB518X6X9Uh.html">Build deliveries locally</a> or via the CI.</p> | the module (for instance, using `npm rebuild` or `npm install`).</code></pre><h3>How the natives are handled</h3><p>Locally, this can be fixed by rebuilding the binaries, which is what <code>npm run electron:switch</code> does, which uses <code>electron-rebuild</code> under the hood.</p><p>When the deliveries are built (see <a class="reference-link type-text" href="UTB518X6X9Uh.html">Build deliveries locally</a>), it is not feasible to rebuild the dependencies since we are building for multiple platforms. Luckily, <code>better-sqlite3</code> provides these prebuilt binaries from us, available as artifacts on <a href="https://github.com/WiseLibs/better-sqlite3/releases/">their GitHub releases page</a>. </p><p>The build script manages the natives for <code>better-sqlite3</code> by keeping a copy of the <code>.node</code> file for every platform in <code>bin/better-sqlite3</code>.</p><p>Whenever the version of <code>better-sqlite3</code> changes, the <code>.node</code> files must also be renewed based on their releases page. To simplify this process, a script was created in <code>bin/better-sqlite3/update.sh</code>.</p><h2>How to update the natives</h2><p>The update script needs to know the version of Electron or Node.js for which to download the prebuilt binaries.</p><p>If you get errors during download, check on the <a href="https://github.com/WiseLibs/better-sqlite3/releases/">releases page</a> to ensure that this particular combination of Electron/Node actually exists for the given release.</p><p>To determine the <code>NODE_MODULE_VERSION</code> that is required, look for <code>This version of Node.js requires</code><br><code>NODE_MODULE_VERSION</code> in the error when starting Trilium via:</p><ul><li><code>npm run electron:start</code> (or run any Electron <a href="UTB518X6X9Uh.html" class="type-text">delivery</a>), case in which the <span style="color:#c0bfbc;"><code>ELECTRON_VERSION</code> variable needs to be changed.</span></li><li><span style="color:#c0bfbc;"><code>npm run server:start</code></span> (or run the Linux server delivery), case in which the <code>NODE_VERSION</code> variable needs to be changed.</li></ul><p>Check which files got changed after running the update script and for each platform that got changed, test it locally via <a class="reference-link type-text" href="UTB518X6X9Uh.html">Build deliveries locally</a> or via the CI.</p> | ||||||
|             </div> |             </div> | ||||||
|          |          | ||||||
|  |  | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ | |||||||
|  |  | ||||||
|          |          | ||||||
|             <div id="content" class="type-text ck-content"> |             <div id="content" class="type-text ck-content"> | ||||||
|                 <h2>Server live reload</h2><p>If running the server using <code>npm run start-server</code>, the server will watch for changes in <code>src/public</code> and trigger a frontend reload if that occurs.</p><h2>Electron live reload</h2><p>Similarly, <code>npm run start-electron</code> supports live refresh  as well.</p><p>However, a core difference is that Electron watches <code>dist/src/public</code> instead of <code>src/public</code> since Electron runs on its own copy of the files.</p><p>To ameliorate that, a separate watch script has been implemented which automatically copies files from <code>src/public</code> to <code>dist/src/public</code> whenever a change is detected. To run it:</p><pre><code class="language-text-plain">npm run </code></pre><h2>Technical details</h2><ul><li>This mechanism is managed at server level by watching for changes in<code>services/ws.ts</code>.</li></ul> |                 <h2>Server live reload</h2><p>If running the server using <code>npm run server:start</code>, the server will watch for changes in <code>src/public</code> and trigger a frontend reload if that occurs.</p><h2>Electron live reload</h2><p>Similarly, <code>npm run electron:start</code> supports live refresh  as well.</p><p>However, a core difference is that Electron watches <code>dist/src/public</code> instead of <code>src/public</code> since Electron runs on its own copy of the files.</p><p>To ameliorate that, a separate watch script has been implemented which automatically copies files from <code>src/public</code> to <code>dist/src/public</code> whenever a change is detected. To run it:</p><pre><code class="language-text-plain">npm run </code></pre><h2>Technical details</h2><ul><li>This mechanism is managed at server level by watching for changes in<code>services/ws.ts</code>.</li></ul> | ||||||
|             </div> |             </div> | ||||||
|          |          | ||||||
|  |  | ||||||
|   | |||||||
| @@ -71,7 +71,7 @@ | |||||||
| <a id="server" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Server<a href="#server" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3><p>To install TriliumNext on your own server (including via Docker from <a href="https://hub.docker.com/r/triliumnext/notes" target="_blank" class="external">Dockerhub</a>) follow <a href="https://triliumnext.github.io/Docs/Wiki/server-installation" target="_blank" class="external">the server installation docs</a>.</p> | <a id="server" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Server<a href="#server" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3><p>To install TriliumNext on your own server (including via Docker from <a href="https://hub.docker.com/r/triliumnext/notes" target="_blank" class="external">Dockerhub</a>) follow <a href="https://triliumnext.github.io/Docs/Wiki/server-installation" target="_blank" class="external">the server installation docs</a>.</p> | ||||||
| <a id="📝-documentation" class="tsd-anchor"></a><h2 class="tsd-anchor-link">📝 Documentation<a href="#📝-documentation" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p><a href="https://triliumnext.github.io/Docs" target="_blank" class="external">See wiki for complete list of documentation pages.</a></p> | <a id="📝-documentation" class="tsd-anchor"></a><h2 class="tsd-anchor-link">📝 Documentation<a href="#📝-documentation" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p><a href="https://triliumnext.github.io/Docs" target="_blank" class="external">See wiki for complete list of documentation pages.</a></p> | ||||||
| <p>You can also read <a href="https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge" target="_blank" class="external">Patterns of personal knowledge base</a> to get some inspiration on how you might use TriliumNext.</p> | <p>You can also read <a href="https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge" target="_blank" class="external">Patterns of personal knowledge base</a> to get some inspiration on how you might use TriliumNext.</p> | ||||||
| <a id="💻-contribute" class="tsd-anchor"></a><h2 class="tsd-anchor-link">💻 Contribute<a href="#💻-contribute" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><a id="code" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Code<a href="#code" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="shell"><span class="hl-0">git</span><span class="hl-1"> </span><span class="hl-3">clone</span><span class="hl-1"> </span><span class="hl-3">https://github.com/TriliumNext/Notes.git</span><br/><span class="hl-0">cd</span><span class="hl-1"> </span><span class="hl-3">Notes</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-3">install</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-3">run</span><span class="hl-1"> </span><span class="hl-3">start-server</span> | <a id="💻-contribute" class="tsd-anchor"></a><h2 class="tsd-anchor-link">💻 Contribute<a href="#💻-contribute" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><a id="code" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Code<a href="#code" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="shell"><span class="hl-0">git</span><span class="hl-1"> </span><span class="hl-3">clone</span><span class="hl-1"> </span><span class="hl-3">https://github.com/TriliumNext/Notes.git</span><br/><span class="hl-0">cd</span><span class="hl-1"> </span><span class="hl-3">Notes</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-3">install</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-3">run</span><span class="hl-1"> </span><span class="hl-3">server:start</span> | ||||||
| </code><button type="button">Copy</button></pre> | </code><button type="button">Copy</button></pre> | ||||||
|  |  | ||||||
| <a id="documentation" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Documentation<a href="#documentation" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Head on over to our <a href="https://github.com/TriliumNext/Docs" target="_blank" class="external">Docs repo</a></p> | <a id="documentation" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Documentation<a href="#documentation" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Head on over to our <a href="https://github.com/TriliumNext/Docs" target="_blank" class="external">Docs repo</a></p> | ||||||
|   | |||||||
| @@ -78,7 +78,7 @@ Trilium 也提供 Flatpak: | |||||||
|  |  | ||||||
| ```shell | ```shell | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## 👏 致谢 | ## 👏 致谢 | ||||||
|   | |||||||
| @@ -86,7 +86,7 @@ Clone localmente y ejecute | |||||||
|  |  | ||||||
| ```shell | ```shell | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## 👏 Reconocimientos | ## 👏 Reconocimientos | ||||||
|   | |||||||
| @@ -73,7 +73,7 @@ Clona localmente ed esegui | |||||||
|  |  | ||||||
| ```shell | ```shell | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## 👏 Riconoscimenti | ## 👏 Riconoscimenti | ||||||
|   | |||||||
| @@ -54,7 +54,7 @@ Trilium は Flatpak としても提供されます: | |||||||
|  |  | ||||||
| ```shell | ```shell | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## 📢 シャウトアウト | ## 📢 シャウトアウト | ||||||
|   | |||||||
| @@ -102,7 +102,7 @@ You can also read [Patterns of personal knowledge base](https://triliumnext.gith | |||||||
| git clone https://github.com/TriliumNext/Notes.git | git clone https://github.com/TriliumNext/Notes.git | ||||||
| cd Notes | cd Notes | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Documentation | ### Documentation | ||||||
|   | |||||||
| @@ -44,7 +44,7 @@ Trilium предоставляется в виде десктопного при | |||||||
|  |  | ||||||
| ```shell | ```shell | ||||||
| npm install | npm install | ||||||
| npm run start-server | npm run server:start | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## 👏 Благодарности | ## 👏 Благодарности | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ | |||||||
|  |  | ||||||
|          |          | ||||||
|             <div id="content" class="type-text ck-content"> |             <div id="content" class="type-text ck-content"> | ||||||
|                 <h3>Run server</h3><p>Run with default settings:</p><pre><code class="language-text-plain">npm run start-server</code></pre><p>Run with custom port:</p><pre><code class="language-text-plain">TRILIUM_PORT=8082 npm run start-server</code></pre><h3>Run Electron</h3><p>Rebuild <code>better-sqlite3</code> dependency:</p><pre><code class="language-text-plain">npm run switch-electron</code></pre><p>Then run Electron:</p><pre><code class="language-text-plain">npm run start-electron</code></pre><p>To run Electron using the same data directory as the production version:</p><pre><code class="language-text-plain">npm run start-electron-no-dir</code></pre><p>When done, switch back the <code>better-sqlite3</code> dependency:</p><pre><code class="language-text-plain">npm run switch-server</code></pre> |                 <h3>Run server</h3><p>Run with default settings:</p><pre><code class="language-text-plain">npm run server:start</code></pre><p>Run with custom port:</p><pre><code class="language-text-plain">TRILIUM_PORT=8082 npm run server:start</code></pre><h3>Run Electron</h3><p>Rebuild <code>better-sqlite3</code> dependency:</p><pre><code class="language-text-plain">npm run electron:switch</code></pre><p>Then run Electron:</p><pre><code class="language-text-plain">npm run electron:start</code></pre><p>To run Electron using the same data directory as the production version:</p><pre><code class="language-text-plain">npm run electron:start-no-dir</code></pre><p>When done, switch back the <code>better-sqlite3</code> dependency:</p><pre><code class="language-text-plain">npm run server:switch</code></pre> | ||||||
|             </div> |             </div> | ||||||
|          |          | ||||||
|  |  | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ | |||||||
|  |  | ||||||
|          |          | ||||||
|             <div id="content" class="type-text ck-content"> |             <div id="content" class="type-text ck-content"> | ||||||
|                 <ul><li>Provides context about when the build was made and the corresponding Git revision.</li><li>The information is displayed to the client when going in the about dialog.</li><li>The build information is hard-coded in <code>src/services/build.ts</code>. This file is generated automatically via <code>npm run update-build-info</code> which itself is run automatically whenever making a build in the CI, or a <a href="UTB518X6X9Uh.html" class="type-text">local delivery</a>.</li></ul> |                 <ul><li>Provides context about when the build was made and the corresponding Git revision.</li><li>The information is displayed to the client when going in the about dialog.</li><li>The build information is hard-coded in <code>src/services/build.ts</code>. This file is generated automatically via <code>npm run chore:update-build-info</code> which itself is run automatically whenever making a build in the CI, or a <a href="UTB518X6X9Uh.html" class="type-text">local delivery</a>.</li></ul> | ||||||
|             </div> |             </div> | ||||||
|          |          | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
							
								
								
									
										2
									
								
								libraries/ckeditor/ckeditor.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
							
								
								
									
										1
									
								
								libraries/codemirror/hcl.js
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -198,6 +198,7 @@ | |||||||
|         ext: [ "hcl " ], |         ext: [ "hcl " ], | ||||||
|         mime: "text/x-hcl", |         mime: "text/x-hcl", | ||||||
|         mode: "hcl", |         mode: "hcl", | ||||||
|  |         name: "Terraform (HCL)" | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										2261
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
							
								
								
									
										137
									
								
								package.json
									
									
									
									
									
								
							
							
						
						| @@ -2,7 +2,7 @@ | |||||||
|   "name": "trilium", |   "name": "trilium", | ||||||
|   "productName": "TriliumNext Notes", |   "productName": "TriliumNext Notes", | ||||||
|   "description": "Build your personal knowledge base with TriliumNext Notes", |   "description": "Build your personal knowledge base with TriliumNext Notes", | ||||||
|   "version": "0.91.6", |   "version": "0.92.2-beta", | ||||||
|   "license": "AGPL-3.0-only", |   "license": "AGPL-3.0-only", | ||||||
|   "main": "./dist/electron-main.js", |   "main": "./dist/electron-main.js", | ||||||
|   "author": { |   "author": { | ||||||
| @@ -20,69 +20,68 @@ | |||||||
|   }, |   }, | ||||||
|   "type": "module", |   "type": "module", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "start-server": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/main.ts", |     "server:start": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/main.ts", | ||||||
|     "start-server-safe": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/main.ts", |     "server:start-safe": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/main.ts", | ||||||
|     "start-server-no-dir": "cross-env TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/main.ts", |     "server:start-no-dir": "cross-env TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/main.ts", | ||||||
|     "start-test-server": "npm run switch-server && rimraf ./data-test && cross-env TRILIUM_DATA_DIR=./data-test TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev TRILIUM_PORT=9999 nodemon src/main.ts", |     "server:start-test": "npm run server:switch && rimraf ./data-test && cross-env TRILIUM_DATA_DIR=./data-test TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev TRILIUM_PORT=9999 nodemon src/main.ts", | ||||||
|     "qstart-server": "npm run switch-server && npm run start-server", |     "server:qstart": "npm run server:switch && npm run server:start", | ||||||
|     "start-electron": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron ./electron-main.ts --inspect=5858 .", |     "server:switch": "rimraf ./node_modules/better-sqlite3 && npm install", | ||||||
|     "start-electron-nix": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./electron-main.ts --inspect=5858 .\"", |     "electron:start": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron ./electron-main.ts --inspect=5858 .", | ||||||
|     "start-electron-no-dir": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_ENV=dev electron --inspect=5858 .", |     "electron:start-no-dir": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_ENV=dev electron --inspect=5858 .", | ||||||
|     "start-electron-no-dir-nix": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./electron-main.ts --inspect=5858 .\"", |     "electron:start-nix": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev nix-shell -p electron_34 --run \"electron ./electron-main.ts --inspect=5858 .\"", | ||||||
|     "start-electron-prod": "npm run prepare-dist && cross-env TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron ./dist/electron-main.js --inspect=5858 .", |     "electron:start-nix-no-dir": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./electron-main.ts --inspect=5858 .\"", | ||||||
|     "start-electron-prod-nix": "electron-rebuild --version 33.3.1 && npm run prepare-dist && cross-env TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./dist/electron-main.js --inspect=5858 .\"", |     "electron:start-prod": "npm run build:prepare-dist && cross-env TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron ./dist/electron-main.js --inspect=5858 .", | ||||||
|     "start-electron-prod-no-dir": "npm run prepare-dist && cross-env TRILIUM_ENV=dev electron --inspect=5858 .", |     "electron:start-prod-no-dir": "npm run build:prepare-dist && cross-env TRILIUM_ENV=dev electron --inspect=5858 .", | ||||||
|     "start-electron-prod-no-dir-nix": "electron-rebuild --version 33.3.1 && npm run prepare-dist && cross-env TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./dist/electron-main.js --inspect=5858 .\"", |     "electron:start-prod-nix": "electron-rebuild --version 33.3.1 && npm run build:prepare-dist && cross-env TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./dist/electron-main.js --inspect=5858 .\"", | ||||||
|     "qstart-electron": "npm run switch-electron && npm run start-electron", |     "electron:start-prod-nix-no-dir": "electron-rebuild --version 33.3.1 && npm run build:prepare-dist && cross-env TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./dist/electron-main.js --inspect=5858 .\"", | ||||||
|     "switch-server": "rimraf ./node_modules/better-sqlite3 && npm install", |     "electron:qstart": "npm run electron:switch && npm run electron:start", | ||||||
|     "switch-electron": "electron-rebuild", |     "electron:switch": "electron-rebuild", | ||||||
|     "build-backend-docs": "rimraf ./docs/backend_api && typedoc ./docs/backend_api src/becca/entities/*.ts src/services/backend_script_api.ts src/services/sql.ts", |     "electron-forge:start": "npm run build:prepare-dist && electron-forge start", | ||||||
|     "build-frontend-docs": "rimraf ./docs/frontend_api && jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/basic_widget.js src/public/app/widgets/note_context_aware_widget.js src/public/app/widgets/right_panel_widget.js", |     "electron-forge:make": "npm run build:prepare-dist && electron-forge make", | ||||||
|     "build-docs": "npm run build-backend-docs && npm run build-frontend-docs", |     "electron-forge:package": "npm run build:prepare-dist && electron-forge package", | ||||||
|     "webpack": "tsx node_modules/webpack/bin/webpack.js -c webpack.config.ts", |     "docs:build-backend": "rimraf ./docs/backend_api && typedoc ./docs/backend_api src/becca/entities/*.ts src/services/backend_script_api.ts src/services/sql.ts", | ||||||
|     "test-playwright": "playwright test", |     "docs:build-frontend": "rimraf ./docs/frontend_api && jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/basic_widget.js src/public/app/widgets/note_context_aware_widget.js src/public/app/widgets/right_panel_widget.js", | ||||||
|     "test": "cross-env TRILIUM_DATA_DIR=./data-test vitest", |     "docs:build": "npm run docs:build-backend && npm run docs:build-frontend", | ||||||
|     "test-coverage": "cross-env TRILIUM_DATA_DIR=./data-test vitest --coverage", |     "build:webpack": "tsx node_modules/webpack/bin/webpack.js -c webpack.config.ts", | ||||||
|     "start-electron-forge": "npm run prepare-dist && electron-forge start", |     "build:prepare-dist": "npm run build:webpack && rimraf ./dist && tsc && tsx ./bin/copy-dist.ts", | ||||||
|     "make-electron": "npm run webpack && npm run prepare-dist && electron-forge make", |     "test": "cross-env TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest", | ||||||
|     "package-electron": "electron-forge package", |     "test:coverage": "cross-env TRILIUM_DATA_DIR=./integration-tests/db vitest --coverage", | ||||||
|     "prepare-dist": "rimraf ./dist && tsc && tsx ./bin/copy-dist.ts", |     "test:playwright": "playwright test", | ||||||
|     "watch-dist": "tsx ./bin/watch-dist.ts", |     "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", | ||||||
|     "update-build-info": "tsx bin/update-build-info.ts", |     "test:integration-mem-db": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts", | ||||||
|     "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", |     "test:integration-mem-db-dev": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts", | ||||||
|     "integration-mem-db": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts", |     "dev:watch-dist": "tsx ./bin/watch-dist.ts", | ||||||
|     "integration-mem-db-dev": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts", |     "dev:prettier-check": "prettier . --check", | ||||||
|     "generate-document": "cross-env nodemon ./bin/generate_document.ts 1000", |     "dev:prettier-fix": "prettier . --write", | ||||||
|     "ci-update-nightly-version": "tsx ./bin/update-nightly-version.ts", |     "chore:update-build-info": "tsx bin/update-build-info.ts", | ||||||
|     "prettier-check": "prettier . --check", |     "chore:ci-update-nightly-version": "tsx ./bin/update-nightly-version.ts", | ||||||
|     "prettier-fix": "prettier . --write" |     "chore:generate-document": "cross-env nodemon ./bin/generate_document.ts 1000", | ||||||
|  |     "chore:generate-openapi": "tsx bin/generate-openapi.js" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@braintree/sanitize-url": "7.1.1", |     "@braintree/sanitize-url": "7.1.1", | ||||||
|     "@electron/remote": "2.1.2", |     "@electron/remote": "2.1.2", | ||||||
|     "@excalidraw/excalidraw": "0.17.6", |     "@excalidraw/excalidraw": "0.17.6", | ||||||
|  |     "@fullcalendar/core": "6.1.15", | ||||||
|  |     "@fullcalendar/daygrid": "6.1.15", | ||||||
|  |     "@fullcalendar/interaction": "6.1.15", | ||||||
|     "@highlightjs/cdn-assets": "11.11.1", |     "@highlightjs/cdn-assets": "11.11.1", | ||||||
|     "@joplin/turndown-plugin-gfm": "1.0.61", |     "@joplin/turndown-plugin-gfm": "1.0.61", | ||||||
|     "@mermaid-js/layout-elk": "0.1.7", |     "@mermaid-js/layout-elk": "0.1.7", | ||||||
|     "@mind-elixir/node-menu": "1.0.4", |     "@mind-elixir/node-menu": "1.0.4", | ||||||
|     "@triliumnext/express-partial-content": "1.0.1", |     "@triliumnext/express-partial-content": "1.0.1", | ||||||
|     "@types/jquery.fancytree": "0.0.11", |  | ||||||
|     "@types/js-yaml": "4.0.9", |  | ||||||
|     "@types/leaflet": "1.9.16", |  | ||||||
|     "@types/react-dom": "18.3.5", |  | ||||||
|     "@types/swagger-ui-express": "4.1.7", |  | ||||||
|     "archiver": "7.0.1", |     "archiver": "7.0.1", | ||||||
|     "async-mutex": "0.5.0", |     "async-mutex": "0.5.0", | ||||||
|     "autocomplete.js": "0.38.1", |     "autocomplete.js": "0.38.1", | ||||||
|     "axios": "1.7.9", |     "axios": "1.7.9", | ||||||
|     "better-sqlite3": "11.8.1", |     "better-sqlite3": "11.8.1", | ||||||
|     "bootstrap": "5.3.3", |  | ||||||
|     "boxicons": "2.1.4", |     "boxicons": "2.1.4", | ||||||
|  |     "chardet": "2.0.0", | ||||||
|     "cheerio": "1.0.0", |     "cheerio": "1.0.0", | ||||||
|     "chokidar": "4.0.3", |     "chokidar": "4.0.3", | ||||||
|     "cls-hooked": "4.2.2", |     "cls-hooked": "4.2.2", | ||||||
|     "codemirror": "5.65.18", |     "codemirror": "5.65.18", | ||||||
|     "compression": "1.7.5", |     "compression": "1.8.0", | ||||||
|     "cookie-parser": "1.4.7", |     "cookie-parser": "1.4.7", | ||||||
|     "csrf-csrf": "3.1.0", |     "csrf-csrf": "3.1.0", | ||||||
|     "dayjs": "1.11.13", |     "dayjs": "1.11.13", | ||||||
| @@ -144,6 +143,7 @@ | |||||||
|     "source-map-support": "0.5.21", |     "source-map-support": "0.5.21", | ||||||
|     "split.js": "1.6.5", |     "split.js": "1.6.5", | ||||||
|     "stream-throttle": "0.1.3", |     "stream-throttle": "0.1.3", | ||||||
|  |     "strip-bom": "5.0.0", | ||||||
|     "striptags": "3.2.0", |     "striptags": "3.2.0", | ||||||
|     "swagger-ui-express": "5.0.1", |     "swagger-ui-express": "5.0.1", | ||||||
|     "tmp": "0.2.3", |     "tmp": "0.2.3", | ||||||
| @@ -151,21 +151,22 @@ | |||||||
|     "turndown": "7.2.0", |     "turndown": "7.2.0", | ||||||
|     "unescape": "1.0.1", |     "unescape": "1.0.1", | ||||||
|     "vanilla-js-wheel-zoom": "9.0.4", |     "vanilla-js-wheel-zoom": "9.0.4", | ||||||
|     "ws": "8.18.0", |     "ws": "8.18.1", | ||||||
|     "xml2js": "0.6.2", |     "xml2js": "0.6.2", | ||||||
|     "yauzl": "3.2.0" |     "yauzl": "3.2.0" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@electron-forge/cli": "7.6.1", |     "@electron-forge/cli": "7.7.0", | ||||||
|     "@electron-forge/maker-deb": "7.6.1", |     "@electron-forge/maker-deb": "7.7.0", | ||||||
|     "@electron-forge/maker-dmg": "7.6.1", |     "@electron-forge/maker-dmg": "7.7.0", | ||||||
|     "@electron-forge/maker-flatpak": "7.6.1", |     "@electron-forge/maker-flatpak": "7.7.0", | ||||||
|     "@electron-forge/maker-rpm": "7.6.1", |     "@electron-forge/maker-rpm": "7.7.0", | ||||||
|     "@electron-forge/maker-squirrel": "7.6.1", |     "@electron-forge/maker-squirrel": "7.7.0", | ||||||
|     "@electron-forge/maker-zip": "7.6.1", |     "@electron-forge/maker-zip": "7.7.0", | ||||||
|     "@electron-forge/plugin-auto-unpack-natives": "7.6.1", |     "@electron-forge/plugin-auto-unpack-natives": "7.7.0", | ||||||
|     "@electron/rebuild": "3.7.1", |     "@electron/rebuild": "3.7.1", | ||||||
|     "@playwright/test": "1.50.1", |     "@playwright/test": "1.50.1", | ||||||
|  |     "@popperjs/core": "2.11.8", | ||||||
|     "@types/archiver": "6.0.3", |     "@types/archiver": "6.0.3", | ||||||
|     "@types/better-sqlite3": "7.6.12", |     "@types/better-sqlite3": "7.6.12", | ||||||
|     "@types/bootstrap": "5.2.10", |     "@types/bootstrap": "5.2.10", | ||||||
| @@ -182,14 +183,17 @@ | |||||||
|     "@types/fs-extra": "11.0.4", |     "@types/fs-extra": "11.0.4", | ||||||
|     "@types/html": "1.0.4", |     "@types/html": "1.0.4", | ||||||
|     "@types/ini": "4.1.1", |     "@types/ini": "4.1.1", | ||||||
|     "@types/jasmine": "5.1.5", |  | ||||||
|     "@types/jquery": "3.5.32", |     "@types/jquery": "3.5.32", | ||||||
|  |     "@types/jquery.fancytree": "0.0.11", | ||||||
|  |     "@types/js-yaml": "4.0.9", | ||||||
|     "@types/jsdom": "21.1.7", |     "@types/jsdom": "21.1.7", | ||||||
|  |     "@types/leaflet": "1.9.16", | ||||||
|     "@types/leaflet-gpx": "1.3.7", |     "@types/leaflet-gpx": "1.3.7", | ||||||
|     "@types/mime-types": "2.1.4", |     "@types/mime-types": "2.1.4", | ||||||
|     "@types/multer": "1.4.12", |     "@types/multer": "1.4.12", | ||||||
|     "@types/node": "22.13.1", |     "@types/node": "22.13.5", | ||||||
|     "@types/react": "18.3.18", |     "@types/react": "18.3.18", | ||||||
|  |     "@types/react-dom": "18.3.5", | ||||||
|     "@types/safe-compare": "1.1.2", |     "@types/safe-compare": "1.1.2", | ||||||
|     "@types/sanitize-html": "2.13.0", |     "@types/sanitize-html": "2.13.0", | ||||||
|     "@types/sax": "1.2.7", |     "@types/sax": "1.2.7", | ||||||
| @@ -197,27 +201,36 @@ | |||||||
|     "@types/session-file-store": "1.2.5", |     "@types/session-file-store": "1.2.5", | ||||||
|     "@types/source-map-support": "0.5.10", |     "@types/source-map-support": "0.5.10", | ||||||
|     "@types/stream-throttle": "0.1.4", |     "@types/stream-throttle": "0.1.4", | ||||||
|  |     "@types/swagger-ui-express": "4.1.8", | ||||||
|     "@types/tmp": "0.2.6", |     "@types/tmp": "0.2.6", | ||||||
|     "@types/turndown": "5.0.5", |     "@types/turndown": "5.0.5", | ||||||
|     "@types/ws": "8.5.14", |     "@types/ws": "8.5.14", | ||||||
|     "@types/xml2js": "0.4.14", |     "@types/xml2js": "0.4.14", | ||||||
|     "@types/yargs": "17.0.33", |     "@types/yargs": "17.0.33", | ||||||
|     "@vitest/coverage-v8": "3.0.5", |     "@vitest/coverage-v8": "3.0.6", | ||||||
|  |     "autoprefixer": "10.4.20", | ||||||
|  |     "bootstrap": "5.3.3", | ||||||
|     "cross-env": "7.0.3", |     "cross-env": "7.0.3", | ||||||
|     "electron": "34.1.1", |     "css-loader": "7.1.2", | ||||||
|  |     "electron": "34.2.0", | ||||||
|     "esm": "3.2.25", |     "esm": "3.2.25", | ||||||
|     "jsdoc": "4.0.4", |     "jsdoc": "4.0.4", | ||||||
|     "lorem-ipsum": "2.0.8", |     "lorem-ipsum": "2.0.8", | ||||||
|  |     "mini-css-extract-plugin": "2.9.2", | ||||||
|     "nodemon": "3.1.9", |     "nodemon": "3.1.9", | ||||||
|     "prettier": "3.5.0", |     "postcss-loader": "8.1.1", | ||||||
|  |     "prettier": "3.5.2", | ||||||
|     "rcedit": "4.0.1", |     "rcedit": "4.0.1", | ||||||
|     "rimraf": "6.0.1", |     "rimraf": "6.0.1", | ||||||
|  |     "sass": "1.85.0", | ||||||
|  |     "sass-loader": "16.0.5", | ||||||
|  |     "swagger-jsdoc": "6.2.8", | ||||||
|     "tslib": "2.8.1", |     "tslib": "2.8.1", | ||||||
|     "tsx": "4.19.2", |     "tsx": "4.19.3", | ||||||
|     "typedoc": "0.27.7", |     "typedoc": "0.27.8", | ||||||
|     "typescript": "5.7.3", |     "typescript": "5.7.3", | ||||||
|     "vitest": "3.0.5", |     "vitest": "3.0.6", | ||||||
|     "webpack": "5.97.1", |     "webpack": "5.98.0", | ||||||
|     "webpack-cli": "6.0.1", |     "webpack-cli": "6.0.1", | ||||||
|     "webpack-dev-middleware": "7.4.2" |     "webpack-dev-middleware": "7.4.2" | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -74,7 +74,7 @@ export default defineConfig({ | |||||||
|  |  | ||||||
|   /* Run your local dev server before starting the tests */ |   /* Run your local dev server before starting the tests */ | ||||||
|   webServer: !process.env.TRILIUM_DOCKER ? { |   webServer: !process.env.TRILIUM_DOCKER ? { | ||||||
|     command: 'npm run integration-mem-db-dev', |     command: 'npm run test:integration-mem-db-dev', | ||||||
|     url: SERVER_URL, |     url: SERVER_URL, | ||||||
|     reuseExistingServer: !process.env.CI, |     reuseExistingServer: !process.env.CI, | ||||||
|   } : undefined, |   } : undefined, | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| import etapi from "../support/etapi.js"; | import etapi from "../support/etapi.js"; | ||||||
|  | /* TriliumNextTODO: port to Vitest  | ||||||
| etapi.describeEtapi("app_info", () => { | etapi.describeEtapi("app_info", () => { | ||||||
|     it("get", async () => { |     it("get", async () => { | ||||||
|         const appInfo = await etapi.getEtapi("app-info"); |         const appInfo = await etapi.getEtapi("app-info"); | ||||||
|         expect(appInfo.clipperProtocolVersion).toEqual("1.0"); |         expect(appInfo.clipperProtocolVersion).toEqual("1.0"); | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|  | */ | ||||||
| @@ -1,8 +1,10 @@ | |||||||
| import etapi from "../support/etapi.js"; | import etapi from "../support/etapi.js"; | ||||||
|  |  | ||||||
|  | /* TriliumNextTODO: port to Vitest | ||||||
| etapi.describeEtapi("backup", () => { | etapi.describeEtapi("backup", () => { | ||||||
|     it("create", async () => { |     it("create", async () => { | ||||||
|         const response = await etapi.putEtapiContent("backup/etapi_test"); |         const response = await etapi.putEtapiContent("backup/etapi_test"); | ||||||
|         expect(response.status).toEqual(204); |         expect(response.status).toEqual(204); | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|  | */ | ||||||
| @@ -3,6 +3,7 @@ import fs from "fs"; | |||||||
| import path from "path"; | import path from "path"; | ||||||
| import { fileURLToPath } from "url"; | import { fileURLToPath } from "url"; | ||||||
|  |  | ||||||
|  | /* TriliumNextTODO: port to Vitest  | ||||||
| etapi.describeEtapi("import", () => { | etapi.describeEtapi("import", () => { | ||||||
|     // temporarily skip this test since test-export.zip is missing |     // temporarily skip this test since test-export.zip is missing | ||||||
|     xit("import", async () => { |     xit("import", async () => { | ||||||
| @@ -22,3 +23,4 @@ etapi.describeEtapi("import", () => { | |||||||
|         expect(content).toContain("test export content"); |         expect(content).toContain("test export content"); | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|  | */ | ||||||
| @@ -1,6 +1,7 @@ | |||||||
| import crypto from "crypto"; | import crypto from "crypto"; | ||||||
| import etapi from "../support/etapi.js"; | import etapi from "../support/etapi.js"; | ||||||
|  |  | ||||||
|  | /* TriliumNextTODO: port to Vitest | ||||||
| etapi.describeEtapi("notes", () => { | etapi.describeEtapi("notes", () => { | ||||||
|     it("create", async () => { |     it("create", async () => { | ||||||
|         const { note, branch } = await etapi.postEtapi("create-note", { |         const { note, branch } = await etapi.postEtapi("create-note", { | ||||||
| @@ -99,3 +100,4 @@ etapi.describeEtapi("notes", () => { | |||||||
|         expect(error.message).toEqual(`Note '${note.noteId}' not found.`); |         expect(error.message).toEqual(`Note '${note.noteId}' not found.`); | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|  | */ | ||||||
| @@ -1,4 +1,5 @@ | |||||||
| import type child_process from "child_process"; | import type child_process from "child_process"; | ||||||
|  | import { describe, beforeAll, afterAll } from "vitest"; | ||||||
|  |  | ||||||
| let etapiAuthToken: string | undefined; | let etapiAuthToken: string | undefined; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,3 +1,35 @@ | |||||||
|  | /** | ||||||
|  |  * Reads the level of indentation of the first line and trims the identation for all the text by that amount. | ||||||
|  |  * | ||||||
|  |  * For example, for: | ||||||
|  |  * | ||||||
|  |  * ```json | ||||||
|  |  *          { | ||||||
|  |  *              "hello": "world" | ||||||
|  |  *          } | ||||||
|  |  * ``` | ||||||
|  |  * | ||||||
|  |  * it results in: | ||||||
|  |  * | ||||||
|  |  * ```json | ||||||
|  |  * { | ||||||
|  |  *     "hello": "world" | ||||||
|  |  * } | ||||||
|  |  * ``` | ||||||
|  |  * | ||||||
|  |  * This is meant to be used as a template string, where it allows the indentation of the template without affecting whitespace changes. | ||||||
|  |  * | ||||||
|  |  * @example const html = trimIndentation`\ | ||||||
|  |  *           <h1>Heading 1</h1> | ||||||
|  |  *           <h2>Heading 2</h2> | ||||||
|  |  *           <h3>Heading 3</h3> | ||||||
|  |  *           <h4>Heading 4</h4> | ||||||
|  |  *           <h5>Heading 5</h5> | ||||||
|  |  *           <h6>Heading 6</h6> | ||||||
|  |  *       `; | ||||||
|  |  * @param strings | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
| export function trimIndentation(strings: TemplateStringsArray) { | export function trimIndentation(strings: TemplateStringsArray) { | ||||||
|     const str = strings.toString(); |     const str = strings.toString(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ import type { AttachmentRow, BlobRow, RevisionRow } from "./entities/rows.js"; | |||||||
| import BBlob from "./entities/bblob.js"; | import BBlob from "./entities/bblob.js"; | ||||||
| import BRecentNote from "./entities/brecent_note.js"; | import BRecentNote from "./entities/brecent_note.js"; | ||||||
| import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js"; | import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js"; | ||||||
|  | import type BTask from "./entities/btask.js"; | ||||||
|  |  | ||||||
| interface AttachmentOpts { | interface AttachmentOpts { | ||||||
|     includeContentLength?: boolean; |     includeContentLength?: boolean; | ||||||
| @@ -32,6 +33,7 @@ export default class Becca { | |||||||
|     attributeIndex!: Record<string, BAttribute[]>; |     attributeIndex!: Record<string, BAttribute[]>; | ||||||
|     options!: Record<string, BOption>; |     options!: Record<string, BOption>; | ||||||
|     etapiTokens!: Record<string, BEtapiToken>; |     etapiTokens!: Record<string, BEtapiToken>; | ||||||
|  |     tasks!: Record<string, BTask>; | ||||||
|  |  | ||||||
|     allNoteSetCache: NoteSet | null; |     allNoteSetCache: NoteSet | null; | ||||||
|  |  | ||||||
| @@ -48,6 +50,7 @@ export default class Becca { | |||||||
|         this.attributeIndex = {}; |         this.attributeIndex = {}; | ||||||
|         this.options = {}; |         this.options = {}; | ||||||
|         this.etapiTokens = {}; |         this.etapiTokens = {}; | ||||||
|  |         this.tasks = {}; | ||||||
|  |  | ||||||
|         this.dirtyNoteSetCache(); |         this.dirtyNoteSetCache(); | ||||||
|  |  | ||||||
| @@ -213,6 +216,14 @@ export default class Becca { | |||||||
|         return this.etapiTokens[etapiTokenId]; |         return this.etapiTokens[etapiTokenId]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     getTasks(): BTask[] { | ||||||
|  |         return Object.values(this.tasks); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getTask(taskId: string): BTask | null { | ||||||
|  |         return this.tasks[taskId]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     getEntity<T extends AbstractBeccaEntity<T>>(entityName: string, entityId: string): AbstractBeccaEntity<T> | null { |     getEntity<T extends AbstractBeccaEntity<T>>(entityName: string, entityId: string): AbstractBeccaEntity<T> | null { | ||||||
|         if (!entityName || !entityId) { |         if (!entityName || !entityId) { | ||||||
|             return null; |             return null; | ||||||
|   | |||||||
| @@ -11,9 +11,10 @@ import BOption from "./entities/boption.js"; | |||||||
| import BEtapiToken from "./entities/betapi_token.js"; | import BEtapiToken from "./entities/betapi_token.js"; | ||||||
| import cls from "../services/cls.js"; | import cls from "../services/cls.js"; | ||||||
| import entityConstructor from "../becca/entity_constructor.js"; | import entityConstructor from "../becca/entity_constructor.js"; | ||||||
| import type { AttributeRow, BranchRow, EtapiTokenRow, NoteRow, OptionRow } from "./entities/rows.js"; | import type { AttributeRow, BranchRow, EtapiTokenRow, NoteRow, OptionRow, TaskRow } from "./entities/rows.js"; | ||||||
| import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js"; | import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js"; | ||||||
| import ws from "../services/ws.js"; | import ws from "../services/ws.js"; | ||||||
|  | import BTask from "./entities/btask.js"; | ||||||
|  |  | ||||||
| const beccaLoaded = new Promise<void>(async (res, rej) => { | const beccaLoaded = new Promise<void>(async (res, rej) => { | ||||||
|     const sqlInit = (await import("../services/sql_init.js")).default; |     const sqlInit = (await import("../services/sql_init.js")).default; | ||||||
| @@ -63,6 +64,10 @@ function load() { | |||||||
|         for (const row of sql.getRows<EtapiTokenRow>(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) { |         for (const row of sql.getRows<EtapiTokenRow>(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) { | ||||||
|             new BEtapiToken(row); |             new BEtapiToken(row); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         for (const row of sql.getRows<TaskRow>(`SELECT taskId, parentNoteId, title, dueDate, isDone, isDeleted FROM tasks WHERE isDeleted = 0`)) { | ||||||
|  |             new BTask(row); | ||||||
|  |         } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     for (const noteId in becca.notes) { |     for (const noteId in becca.notes) { | ||||||
|   | |||||||
| @@ -159,7 +159,7 @@ class BBranch extends AbstractBeccaEntity<BBranch> { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (this.noteId === "root" || this.noteId === cls.getHoistedNoteId()) { |         if ((this.noteId === "root" || this.noteId === cls.getHoistedNoteId()) && !this.isWeak) { | ||||||
|             throw new Error("Can't delete root or hoisted branch/note"); |             throw new Error("Can't delete root or hoisted branch/note"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										84
									
								
								src/becca/entities/btask.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,84 @@ | |||||||
|  | import date_utils from "../../services/date_utils.js"; | ||||||
|  | import AbstractBeccaEntity from "./abstract_becca_entity.js"; | ||||||
|  | import type BOption from "./boption.js"; | ||||||
|  | import type { TaskRow } from "./rows.js"; | ||||||
|  |  | ||||||
|  | export default class BTask extends AbstractBeccaEntity<BOption> { | ||||||
|  |  | ||||||
|  |     static get entityName() { | ||||||
|  |         return "tasks"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get primaryKeyName() { | ||||||
|  |         return "taskId"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static get hashedProperties() { | ||||||
|  |         return [ "taskId", "parentNoteId", "title", "dueDate", "isDone", "isDeleted" ]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     taskId?: string; | ||||||
|  |     parentNoteId!: string; | ||||||
|  |     title!: string; | ||||||
|  |     dueDate?: string; | ||||||
|  |     isDone!: boolean; | ||||||
|  |     private _isDeleted?: boolean; | ||||||
|  |  | ||||||
|  |     constructor(row?: TaskRow) { | ||||||
|  |         super(); | ||||||
|  |  | ||||||
|  |         if (!row) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.updateFromRow(row); | ||||||
|  |         this.init(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get isDeleted() { | ||||||
|  |         return !!this._isDeleted; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     updateFromRow(row: TaskRow) { | ||||||
|  |         this.taskId = row.taskId; | ||||||
|  |         this.parentNoteId = row.parentNoteId; | ||||||
|  |         this.title = row.title; | ||||||
|  |         this.dueDate = row.dueDate; | ||||||
|  |         this.isDone = !!row.isDone; | ||||||
|  |         this._isDeleted = !!row.isDeleted; | ||||||
|  |         this.utcDateModified = row.utcDateModified; | ||||||
|  |  | ||||||
|  |         if (this.taskId) { | ||||||
|  |             this.becca.tasks[this.taskId] = this; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     init() { | ||||||
|  |         if (this.taskId) { | ||||||
|  |             this.becca.tasks[this.taskId] = this; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected beforeSaving(opts?: {}): void { | ||||||
|  |         super.beforeSaving(); | ||||||
|  |  | ||||||
|  |         this.utcDateModified = date_utils.utcNowDateTime(); | ||||||
|  |  | ||||||
|  |         if (this.taskId) { | ||||||
|  |             this.becca.tasks[this.taskId] = this; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getPojo() { | ||||||
|  |         return { | ||||||
|  |             taskId: this.taskId, | ||||||
|  |             parentNoteId: this.parentNoteId, | ||||||
|  |             title: this.title, | ||||||
|  |             dueDate: this.dueDate, | ||||||
|  |             isDone: this.isDone, | ||||||
|  |             isDeleted: this.isDeleted, | ||||||
|  |             utcDateModified: this.utcDateModified | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -1,4 +1,5 @@ | |||||||
| // TODO: Booleans should probably be numbers instead (as SQLite does not have booleans.); | // TODO: Booleans should probably be numbers instead (as SQLite does not have booleans.); | ||||||
|  | // TODO: check against schema.sql which properties really are "optional" | ||||||
|  |  | ||||||
| export interface AttachmentRow { | export interface AttachmentRow { | ||||||
|     attachmentId?: string; |     attachmentId?: string; | ||||||
| @@ -12,6 +13,8 @@ export interface AttachmentRow { | |||||||
|     dateModified?: string; |     dateModified?: string; | ||||||
|     utcDateModified?: string; |     utcDateModified?: string; | ||||||
|     utcDateScheduledForErasureSince?: string; |     utcDateScheduledForErasureSince?: string; | ||||||
|  |     isDeleted?: boolean; | ||||||
|  |     deleteId?: string; | ||||||
|     contentLength?: number; |     contentLength?: number; | ||||||
|     content?: Buffer | string; |     content?: Buffer | string; | ||||||
| } | } | ||||||
| @@ -136,3 +139,13 @@ export interface NoteRow { | |||||||
|     utcDateModified: string; |     utcDateModified: string; | ||||||
|     content?: string | Buffer; |     content?: string | Buffer; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export interface TaskRow { | ||||||
|  |     taskId?: string; | ||||||
|  |     parentNoteId: string; | ||||||
|  |     title: string; | ||||||
|  |     dueDate?: string; | ||||||
|  |     isDone?: boolean; | ||||||
|  |     isDeleted?: boolean; | ||||||
|  |     utcDateModified?: string; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import BNote from "./entities/bnote.js"; | |||||||
| import BOption from "./entities/boption.js"; | import BOption from "./entities/boption.js"; | ||||||
| import BRecentNote from "./entities/brecent_note.js"; | import BRecentNote from "./entities/brecent_note.js"; | ||||||
| import BRevision from "./entities/brevision.js"; | import BRevision from "./entities/brevision.js"; | ||||||
|  | import BTask from "./entities/btask.js"; | ||||||
|  |  | ||||||
| type EntityClass = new (row?: any) => AbstractBeccaEntity<any>; | type EntityClass = new (row?: any) => AbstractBeccaEntity<any>; | ||||||
|  |  | ||||||
| @@ -21,7 +22,8 @@ const ENTITY_NAME_TO_ENTITY: Record<string, ConstructorData<any> & EntityClass> | |||||||
|     notes: BNote, |     notes: BNote, | ||||||
|     options: BOption, |     options: BOption, | ||||||
|     recent_notes: BRecentNote, |     recent_notes: BRecentNote, | ||||||
|     revisions: BRevision |     revisions: BRevision, | ||||||
|  |     tasks: BTask | ||||||
| }; | }; | ||||||
|  |  | ||||||
| function getEntityFromEntityName(entityName: keyof typeof ENTITY_NAME_TO_ENTITY) { | function getEntityFromEntityName(entityName: keyof typeof ENTITY_NAME_TO_ENTITY) { | ||||||
|   | |||||||
| @@ -80,6 +80,7 @@ export type CommandMappings = { | |||||||
|     }; |     }; | ||||||
|     closeTocCommand: CommandData; |     closeTocCommand: CommandData; | ||||||
|     showLaunchBarSubtree: CommandData; |     showLaunchBarSubtree: CommandData; | ||||||
|  |     showRevisions: CommandData; | ||||||
|     showOptions: CommandData & { |     showOptions: CommandData & { | ||||||
|         section: string; |         section: string; | ||||||
|     }; |     }; | ||||||
| @@ -106,10 +107,6 @@ export type CommandMappings = { | |||||||
|     showInfoDialog: ConfirmWithMessageOptions; |     showInfoDialog: ConfirmWithMessageOptions; | ||||||
|     showConfirmDialog: ConfirmWithMessageOptions; |     showConfirmDialog: ConfirmWithMessageOptions; | ||||||
|     showRecentChanges: CommandData & { ancestorNoteId: string }; |     showRecentChanges: CommandData & { ancestorNoteId: string }; | ||||||
|     showExportDialog: CommandData & { |  | ||||||
|         notePath: string; |  | ||||||
|         defaultType: "subtree" |  | ||||||
|     }; |  | ||||||
|     showImportDialog: CommandData & { noteId: string; }; |     showImportDialog: CommandData & { noteId: string; }; | ||||||
|     openNewNoteSplit: NoteCommandData; |     openNewNoteSplit: NoteCommandData; | ||||||
|     openInWindow: NoteCommandData; |     openInWindow: NoteCommandData; | ||||||
| @@ -119,6 +116,8 @@ export type CommandMappings = { | |||||||
|     hideLeftPane: CommandData; |     hideLeftPane: CommandData; | ||||||
|     showLeftPane: CommandData; |     showLeftPane: CommandData; | ||||||
|     hoistNote: CommandData & { noteId: string }; |     hoistNote: CommandData & { noteId: string }; | ||||||
|  |     leaveProtectedSession: CommandData; | ||||||
|  |     enterProtectedSession: CommandData; | ||||||
|  |  | ||||||
|     openInTab: ContextMenuCommandData; |     openInTab: ContextMenuCommandData; | ||||||
|     openNoteInSplit: ContextMenuCommandData; |     openNoteInSplit: ContextMenuCommandData; | ||||||
| @@ -225,10 +224,18 @@ export type CommandMappings = { | |||||||
|  |  | ||||||
|     reEvaluateRightPaneVisibility: CommandData; |     reEvaluateRightPaneVisibility: CommandData; | ||||||
|     runActiveNote: CommandData; |     runActiveNote: CommandData; | ||||||
|  |     scrollContainerToCommand: CommandData & { | ||||||
|  |         position: number; | ||||||
|  |     }; | ||||||
|  |     moveThisNoteSplit: CommandData & { | ||||||
|  |         isMovingLeft: boolean; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     // Geomap |     // Geomap | ||||||
|     deleteFromMap: { noteId: string }, |     deleteFromMap: { noteId: string }, | ||||||
|     openGeoLocation: { noteId: string, event: JQuery.MouseDownEvent } |     openGeoLocation: { noteId: string, event: JQuery.MouseDownEvent } | ||||||
|  |  | ||||||
|  |     toggleZenMode: CommandData; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| type EventMappings = { | type EventMappings = { | ||||||
| @@ -306,6 +313,7 @@ type EventMappings = { | |||||||
|     noteContextReorderEvent: { |     noteContextReorderEvent: { | ||||||
|         oldMainNtxId: string; |         oldMainNtxId: string; | ||||||
|         newMainNtxId: string; |         newMainNtxId: string; | ||||||
|  |         ntxIdsInOrder: string[]; | ||||||
|     }; |     }; | ||||||
|     newNoteContextCreated: { |     newNoteContextCreated: { | ||||||
|         noteContext: NoteContext; |         noteContext: NoteContext; | ||||||
| @@ -314,7 +322,7 @@ type EventMappings = { | |||||||
|         ntxIds: string[]; |         ntxIds: string[]; | ||||||
|     }; |     }; | ||||||
|     exportSvg: { |     exportSvg: { | ||||||
|         ntxId: string; |         ntxId: string | null | undefined; | ||||||
|     }; |     }; | ||||||
|     geoMapCreateChildNote: { |     geoMapCreateChildNote: { | ||||||
|         ntxId: string | null | undefined; // TODO: deduplicate ntxId |         ntxId: string | null | undefined; // TODO: deduplicate ntxId | ||||||
| @@ -330,6 +338,7 @@ type EventMappings = { | |||||||
|     }; |     }; | ||||||
|     scrollToEnd: { ntxId: string }; |     scrollToEnd: { ntxId: string }; | ||||||
|     noteTypeMimeChanged: { noteId: string }; |     noteTypeMimeChanged: { noteId: string }; | ||||||
|  |     zenModeChanged: { isEnabled: boolean }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export type EventListener<T extends EventNames> = { | export type EventListener<T extends EventNames> = { | ||||||
|   | |||||||
| @@ -290,7 +290,7 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded"> | |||||||
|         return ( |         return ( | ||||||
|             this.note && |             this.note && | ||||||
|             ["default", "contextual-help"].includes(this.viewScope?.viewMode ?? "") && |             ["default", "contextual-help"].includes(this.viewScope?.viewMode ?? "") && | ||||||
|             this.note.hasChildren() && |             (this.note.hasChildren() || this.note.getLabelValue("viewType") === "calendar") && | ||||||
|             ["book", "text", "code"].includes(this.note.type) && |             ["book", "text", "code"].includes(this.note.type) && | ||||||
|             this.note.mime !== "text/x-sqlite;schema=trilium" && |             this.note.mime !== "text/x-sqlite;schema=trilium" && | ||||||
|             !this.note.isLabelTruthy("hideChildrenOverview") |             !this.note.isLabelTruthy("hideChildrenOverview") | ||||||
|   | |||||||
| @@ -178,6 +178,13 @@ export default class RootCommandExecutor extends Component { | |||||||
|         for (const window of windows) window[action](); |         for (const window of windows) window[action](); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     toggleZenModeCommand() { | ||||||
|  |         const $body = $("body"); | ||||||
|  |         $body.toggleClass("zen"); | ||||||
|  |         const isEnabled = $body.hasClass("zen"); | ||||||
|  |         appContext.triggerEvent("zenModeChanged", { isEnabled }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     firstTabCommand() { |     firstTabCommand() { | ||||||
|         this.#goToTab(1); |         this.#goToTab(1); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import { t } from "./services/i18n.js"; | |||||||
| import options from "./services/options.js"; | import options from "./services/options.js"; | ||||||
| import type ElectronRemote from "@electron/remote"; | import type ElectronRemote from "@electron/remote"; | ||||||
| import type Electron from "electron"; | import type Electron from "electron"; | ||||||
|  | import "../stylesheets/bootstrap.scss"; | ||||||
|  |  | ||||||
| await appContext.earlyInit(); | await appContext.earlyInit(); | ||||||
|  |  | ||||||
| @@ -50,6 +51,7 @@ function initOnElectron() { | |||||||
|     const currentWindow = electronRemote.getCurrentWindow(); |     const currentWindow = electronRemote.getCurrentWindow(); | ||||||
|     const style = window.getComputedStyle(document.body); |     const style = window.getComputedStyle(document.body); | ||||||
|  |  | ||||||
|  |     initDarkOrLightMode(style); | ||||||
|     initTransparencyEffects(style, currentWindow); |     initTransparencyEffects(style, currentWindow); | ||||||
|  |  | ||||||
|     if (options.get("nativeTitleBarVisible") !== "true") { |     if (options.get("nativeTitleBarVisible") !== "true") { | ||||||
| @@ -91,3 +93,21 @@ function initTransparencyEffects(style: CSSStyleDeclaration, currentWindow: Elec | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Informs Electron that we prefer a dark or light theme. Apart from changing prefers-color-scheme at CSS level which is a side effect, | ||||||
|  |  * this fixes color issues with background effects or native title bars. | ||||||
|  |  * | ||||||
|  |  * @param style the root CSS element to read variables from. | ||||||
|  |  */ | ||||||
|  | function initDarkOrLightMode(style: CSSStyleDeclaration) { | ||||||
|  |     let themeSource: typeof nativeTheme.themeSource = "system"; | ||||||
|  |  | ||||||
|  |     const themeStyle = style.getPropertyValue("--theme-style"); | ||||||
|  |     if (style.getPropertyValue("--theme-style-auto") !== "true" && (themeStyle === "light" || themeStyle === "dark")) { | ||||||
|  |         themeSource = themeStyle; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const { nativeTheme } = utils.dynamicRequire("@electron/remote") as typeof ElectronRemote; | ||||||
|  |     nativeTheme.themeSource = themeSource; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -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 & 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><protocol>://<host>/custom/hello</code> (where <code><protocol></code> is | ||||||
|  |             either <code>http</code> or <code>https</code> based on your setup, and <code><host></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><host>/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> | ||||||
| Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB | 
| After Width: | Height: | Size: 92 KiB | 
| Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 340 B | 
| After Width: | Height: | Size: 17 KiB | 
| After Width: | Height: | Size: 25 KiB | 
| After Width: | Height: | Size: 125 KiB | 
| After Width: | Height: | Size: 93 KiB | 
| After Width: | Height: | Size: 1.0 KiB | 
| After Width: | Height: | Size: 79 KiB | 
| @@ -5,32 +5,35 @@ | |||||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> |     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|     <link rel="stylesheet" href="../../style.css"> |     <link rel="stylesheet" href="../../style.css"> | ||||||
|     <base target="_parent"> |     <base target="_parent"> | ||||||
|     <title data-trilium-title>Exporting as PDF</title> |     <title data-trilium-title>Export as PDF</title> | ||||||
|   </head> |   </head> | ||||||
|    |    | ||||||
|   <body> |   <body> | ||||||
|     <div class="content"> |     <div class="content"> | ||||||
|        <h1 data-trilium-h1>Exporting as PDF</h1> |        <h1 data-trilium-h1>Export as PDF</h1> | ||||||
| 
 | 
 | ||||||
|       <div class="ck-content"> |       <div class="ck-content"> | ||||||
|         <figure class="image image-style-align-right image_resized" style="width:47.17%;"> |         <figure class="image image-style-align-right image_resized" style="width:50.63%;"> | ||||||
|           <img style="aspect-ratio:951/432;" src="1_Exporting as PDF_image.png" |           <img style="aspect-ratio:951/432;" src="Export as PDF_image.png" width="951" | ||||||
|           width="951" height="432"> |           height="432"> | ||||||
|  |           <figcaption>Screenshot of the note contextual menu indicating the “Export as PDF” | ||||||
|  |             option.</figcaption> | ||||||
|         </figure> |         </figure> | ||||||
|         <p>On the desktop application of Trilium it is possible to export a note |         <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 |           as PDF. On the server or PWA (mobile), the option is not available due | ||||||
|           to technical constraints and it will be hidden.</p> |           to technical constraints and it will be hidden.</p> | ||||||
|         <p>To print a note, select the |         <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> |           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. |         <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. |         <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 table does not fit properly, there is cut off text, etc.) feel free to | ||||||
|           <a |           <a | ||||||
|           href="#root/OeKBfN6JbMIq/jRV1MPt4mNSP/hrC6xn7hnDq5">report the issue</a>. In this case, it's best to offer a sample note (click |           href="#root/OeKBfN6JbMIq/jRV1MPt4mNSP/hrC6xn7hnDq5">report the issue</a>. In this case, it's best to offer a sample note (click | ||||||
|             on the |             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> |             in ZIP archive). Make sure not to accidentally leak any personal information.</p> | ||||||
|         <h2>Landscape mode</h2> |         <h2>Landscape mode</h2> | ||||||
|         <p>When exporting to PDF, there are no customizable settings such as page |         <p>When exporting to PDF, there are no customizable settings such as page | ||||||
| Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB | 
| @@ -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 & 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> </p> | ||||||
|  |         <p> </p> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </body> | ||||||
|  |  | ||||||
|  | </html> | ||||||
| After Width: | Height: | Size: 8.4 KiB | 
| Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB | 
| Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB | 
| Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB | 
| Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB | 
| Before Width: | Height: | Size: 323 KiB After Width: | Height: | Size: 323 KiB | 
| Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB | 
| Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB | 
| Before Width: | Height: | Size: 191 KiB After Width: | Height: | Size: 191 KiB | 
| Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB | 
| Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB | 
| Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB | 
| Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB | 
| Before Width: | Height: | Size: 515 KiB After Width: | Height: | Size: 515 KiB | 
| Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB | 
| Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB | 
| Before Width: | Height: | Size: 397 KiB After Width: | Height: | Size: 397 KiB | 
| Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB | 
| Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB | 
| Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 260 KiB | 
| After Width: | Height: | Size: 10 KiB | 
| After Width: | Height: | Size: 2.2 KiB | 
| After Width: | Height: | Size: 1.8 KiB | 
| After Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 9.7 KiB | 
| After Width: | Height: | Size: 10 KiB | 
| After Width: | Height: | Size: 7.3 KiB |