Merge remote-tracking branch 'origin/develop' into port/client_ts

This commit is contained in:
Elian Doran 2025-02-24 10:14:46 +02:00
commit 147c340529
No known key found for this signature in database
338 changed files with 8874 additions and 2488 deletions

View File

@ -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: |

View File

@ -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

View File

@ -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: |

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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",

View File

@ -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/**"]
} }

View File

@ -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 \

View File

@ -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

View File

@ -78,7 +78,7 @@ Trilium 也提供 Flatpak
```shell ```shell
npm install npm install
npm run start-server npm run server:start
``` ```
## 👏 致谢 ## 👏 致谢

View File

@ -86,7 +86,7 @@ Clone localmente y ejecute
```shell ```shell
npm install npm install
npm run start-server npm run server:start
``` ```
## 👏 Reconocimientos ## 👏 Reconocimientos

View File

@ -73,7 +73,7 @@ Clona localmente ed esegui
```shell ```shell
npm install npm install
npm run start-server npm run server:start
``` ```
## 👏 Riconoscimenti ## 👏 Riconoscimenti

View File

@ -54,7 +54,7 @@ Trilium は Flatpak としても提供されます:
```shell ```shell
npm install npm install
npm run start-server npm run server:start
``` ```
## 📢 シャウトアウト ## 📢 シャウトアウト

View File

@ -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

View File

@ -44,7 +44,7 @@ Trilium предоставляется в виде десктопного при
```shell ```shell
npm install npm install
npm run start-server npm run server:start
``` ```
## 👏 Благодарности ## 👏 Благодарности

View File

@ -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/",

View File

@ -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
View File

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

View File

@ -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

View File

@ -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=

View 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
);

View File

@ -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
);

View File

@ -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&nbsp;<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>.&nbsp;</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&nbsp;<a class="reference-link type-text" href="UTB518X6X9Uh.html">Build deliveries locally</a>&nbsp;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&nbsp;<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>.&nbsp;</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&nbsp;<a class="reference-link type-text" href="UTB518X6X9Uh.html">Build deliveries locally</a>&nbsp;or via the CI.</p>
</div> </div>

View File

@ -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 &nbsp;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 &nbsp;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>

View File

@ -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>

View File

@ -78,7 +78,7 @@ Trilium 也提供 Flatpak
```shell ```shell
npm install npm install
npm run start-server npm run server:start
``` ```
## 👏 致谢 ## 👏 致谢

View File

@ -86,7 +86,7 @@ Clone localmente y ejecute
```shell ```shell
npm install npm install
npm run start-server npm run server:start
``` ```
## 👏 Reconocimientos ## 👏 Reconocimientos

View File

@ -73,7 +73,7 @@ Clona localmente ed esegui
```shell ```shell
npm install npm install
npm run start-server npm run server:start
``` ```
## 👏 Riconoscimenti ## 👏 Riconoscimenti

View File

@ -54,7 +54,7 @@ Trilium は Flatpak としても提供されます:
```shell ```shell
npm install npm install
npm run start-server npm run server:start
``` ```
## 📢 シャウトアウト ## 📢 シャウトアウト

View File

@ -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

View File

@ -44,7 +44,7 @@ Trilium предоставляется в виде десктопного при
```shell ```shell
npm install npm install
npm run start-server npm run server:start
``` ```
## 👏 Благодарности ## 👏 Благодарности

View File

@ -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>

View File

@ -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>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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"
} }

View File

@ -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,

View File

@ -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");
}); });
}); });
*/

View File

@ -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);
}); });
}); });
*/

View File

@ -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");
}); });
}); });
*/

View File

@ -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.`);
}); });
}); });
*/

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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) {

View File

@ -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");
} }

View 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
};
}
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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> = {

View File

@ -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")

View File

@ -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);
} }

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -5,32 +5,35 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Some files were not shown because too many files have changed in this diff Show More