Merge remote-tracking branch 'origin/develop' into style/next/restyle-ckeditor
200
.github/actions/build-electron/action.yml
vendored
@ -1,3 +1,6 @@
|
||||
name: "Build Electron App"
|
||||
description: "Builds and packages the Electron app for different platforms"
|
||||
|
||||
inputs:
|
||||
os:
|
||||
description: "One of the supported platforms: macos, linux, windows"
|
||||
@ -6,34 +9,205 @@ inputs:
|
||||
description: "The architecture to build for: x64, arm64"
|
||||
required: true
|
||||
extension:
|
||||
description: "Platform specific extension to build: dmg, deb, exe"
|
||||
description: "Platform specific extensions to copy in the output: dmg, deb, rpm, exe, zip"
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Set up Python for appdmg to be installed
|
||||
# Certificate setup
|
||||
- name: Import Apple certificates
|
||||
if: inputs.os == 'macos'
|
||||
uses: apple-actions/import-codesign-certs@v2
|
||||
with:
|
||||
p12-file-base64: ${{ env.APPLE_APP_CERTIFICATE_BASE64 }}
|
||||
p12-password: ${{ env.APPLE_APP_CERTIFICATE_PASSWORD }}
|
||||
keychain: build
|
||||
keychain-password: ${{ github.run_id }}
|
||||
|
||||
- name: Install Installer certificate
|
||||
if: inputs.os == 'macos'
|
||||
uses: apple-actions/import-codesign-certs@v2
|
||||
with:
|
||||
p12-file-base64: ${{ env.APPLE_INSTALLER_CERTIFICATE_BASE64 }}
|
||||
p12-password: ${{ env.APPLE_INSTALLER_CERTIFICATE_PASSWORD }}
|
||||
keychain: build
|
||||
keychain-password: ${{ github.run_id }}
|
||||
# We don't need to create a keychain here because we're using the build keychain that was created in the previous step
|
||||
create-keychain: false
|
||||
|
||||
- name: Verify certificates
|
||||
if: inputs.os == 'macos'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Available signing identities:"
|
||||
security find-identity -v -p codesigning build.keychain
|
||||
|
||||
- name: Set up Python and other macOS dependencies
|
||||
if: ${{ inputs.os == 'macos' }}
|
||||
shell: bash
|
||||
run: brew install python-setuptools
|
||||
- name: Install rpm on Ubuntu for RPM package building
|
||||
run: |
|
||||
brew install python-setuptools
|
||||
brew install create-dmg
|
||||
|
||||
- name: Install dependencies for RPM and Flatpak package building
|
||||
if: ${{ inputs.os == 'linux' }}
|
||||
shell: bash
|
||||
run: sudo apt install rpm
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install rpm flatpak-builder elfutils
|
||||
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
FLATPAK_ARCH=$(if [[ ${{ inputs.arch }} = 'arm64' ]]; then echo 'aarch64'; else echo 'x86_64'; fi)
|
||||
FLATPAK_VERSION='24.08'
|
||||
flatpak install --user --no-deps --arch $FLATPAK_ARCH --assumeyes runtime/org.freedesktop.Platform/$FLATPAK_ARCH/$FLATPAK_VERSION runtime/org.freedesktop.Sdk/$FLATPAK_ARCH/$FLATPAK_VERSION org.electronjs.Electron2.BaseApp/$FLATPAK_ARCH/$FLATPAK_VERSION
|
||||
|
||||
# Build setup
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: npm ci
|
||||
|
||||
- name: Update build info
|
||||
shell: bash
|
||||
run: npm run update-build-info
|
||||
- name: Run electron-forge
|
||||
run: npm run chore:update-build-info
|
||||
|
||||
# Critical debugging configuration
|
||||
- name: Run electron-forge build with enhanced logging
|
||||
shell: bash
|
||||
run: npm run make-electron -- --arch=${{ inputs.arch }}
|
||||
env:
|
||||
# Pass through required environment variables for signing and notarization
|
||||
APPLE_TEAM_ID: ${{ env.APPLE_TEAM_ID }}
|
||||
APPLE_ID: ${{ env.APPLE_ID }}
|
||||
APPLE_ID_PASSWORD: ${{ env.APPLE_ID_PASSWORD }}
|
||||
run: |
|
||||
# Map OS names to Electron Forge platform names
|
||||
if [ "${{ inputs.os }}" = "macos" ]; then
|
||||
PLATFORM="darwin"
|
||||
elif [ "${{ inputs.os }}" = "windows" ]; then
|
||||
PLATFORM="win32"
|
||||
else
|
||||
PLATFORM="${{ inputs.os }}"
|
||||
fi
|
||||
|
||||
npm run electron-forge:make -- \
|
||||
--arch=${{ inputs.arch }} \
|
||||
--platform=$PLATFORM
|
||||
|
||||
# Add DMG signing step
|
||||
- name: Sign DMG
|
||||
if: inputs.os == 'macos'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Signing DMG file..."
|
||||
dmg_file=$(find out -name "*.dmg" -print -quit)
|
||||
if [ -n "$dmg_file" ]; then
|
||||
echo "Found DMG: $dmg_file"
|
||||
# Get the first valid signing identity from the keychain
|
||||
SIGNING_IDENTITY=$(security find-identity -v -p codesigning build.keychain | grep "Developer ID Application" | head -1 | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [ -z "$SIGNING_IDENTITY" ]; then
|
||||
echo "Error: No valid Developer ID Application certificate found in keychain"
|
||||
exit 1
|
||||
fi
|
||||
echo "Using signing identity: $SIGNING_IDENTITY"
|
||||
# Sign the DMG
|
||||
codesign --force --sign "$SIGNING_IDENTITY" --options runtime --timestamp "$dmg_file"
|
||||
# Notarize the DMG
|
||||
xcrun notarytool submit "$dmg_file" --apple-id "$APPLE_ID" --password "$APPLE_ID_PASSWORD" --team-id "$APPLE_TEAM_ID" --wait
|
||||
# Staple the notarization ticket
|
||||
xcrun stapler staple "$dmg_file"
|
||||
else
|
||||
echo "No DMG found to sign"
|
||||
fi
|
||||
|
||||
- name: Verify code signing
|
||||
if: inputs.os == 'macos'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Verifying code signing for all artifacts..."
|
||||
|
||||
# First check the .app bundle
|
||||
echo "Looking for .app bundle..."
|
||||
app_bundle=$(find out -name "*.app" -print -quit)
|
||||
if [ -n "$app_bundle" ]; then
|
||||
echo "Found app bundle: $app_bundle"
|
||||
echo "Verifying app bundle signing..."
|
||||
codesign --verify --deep --strict --verbose=2 "$app_bundle"
|
||||
echo "Displaying app bundle signing info..."
|
||||
codesign --display --verbose=2 "$app_bundle"
|
||||
|
||||
echo "Checking entitlements..."
|
||||
codesign --display --entitlements :- "$app_bundle"
|
||||
|
||||
echo "Checking notarization status..."
|
||||
xcrun stapler validate "$app_bundle" || echo "Warning: App bundle not notarized yet"
|
||||
else
|
||||
echo "No .app bundle found to verify"
|
||||
fi
|
||||
|
||||
# Then check DMG if it exists
|
||||
echo "Looking for DMG..."
|
||||
dmg_file=$(find out -name "*.dmg" -print -quit)
|
||||
if [ -n "$dmg_file" ]; then
|
||||
echo "Found DMG: $dmg_file"
|
||||
echo "Verifying DMG signing..."
|
||||
codesign --verify --deep --strict --verbose=2 "$dmg_file"
|
||||
echo "Displaying DMG signing info..."
|
||||
codesign --display --verbose=2 "$dmg_file"
|
||||
|
||||
echo "Checking DMG notarization..."
|
||||
xcrun stapler validate "$dmg_file" || echo "Warning: DMG not notarized yet"
|
||||
else
|
||||
echo "No DMG found to verify"
|
||||
fi
|
||||
|
||||
# Finally check ZIP if it exists
|
||||
echo "Looking for ZIP..."
|
||||
zip_file=$(find out -name "*.zip" -print -quit)
|
||||
if [ -n "$zip_file" ]; then
|
||||
echo "Found ZIP: $zip_file"
|
||||
echo "Note: ZIP files are not code signed, but their contents should be"
|
||||
fi
|
||||
|
||||
- name: Prepare artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p upload;
|
||||
for ext in ${{ join(inputs.extension, ' ') }};
|
||||
do
|
||||
file=$(find out/make -name "*.$ext" -print -quit);
|
||||
cp "$file" "upload/TriliumNextNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}.$ext";
|
||||
mkdir -p upload
|
||||
|
||||
if [ "${{ inputs.os }}" = "macos" ]; then
|
||||
# For macOS, we need to look in specific directories based on the maker
|
||||
echo "Collecting macOS artifacts..."
|
||||
|
||||
# Look for DMG files recursively
|
||||
echo "Looking for DMG files..."
|
||||
dmg_file=$(find out -name "*.dmg" -print -quit)
|
||||
if [ -n "$dmg_file" ]; then
|
||||
echo "Found DMG: $dmg_file"
|
||||
cp "$dmg_file" "upload/TriliumNextNotes-${{ github.ref_name }}-darwin-${{ inputs.arch }}.dmg"
|
||||
else
|
||||
echo "Warning: No DMG file found"
|
||||
fi
|
||||
|
||||
# Look for ZIP files recursively
|
||||
echo "Looking for ZIP files..."
|
||||
zip_file=$(find out -name "*.zip" -print -quit)
|
||||
if [ -n "$zip_file" ]; then
|
||||
echo "Found ZIP: $zip_file"
|
||||
cp "$zip_file" "upload/TriliumNextNotes-${{ github.ref_name }}-darwin-${{ inputs.arch }}.zip"
|
||||
else
|
||||
echo "Warning: No ZIP file found"
|
||||
fi
|
||||
else
|
||||
# For other platforms, use the existing logic but with better error handling
|
||||
echo "Collecting artifacts for ${{ inputs.os }}..."
|
||||
for ext in ${{ inputs.extension }}; do
|
||||
echo "Looking for .$ext files..."
|
||||
file=$(find out -name "*.$ext" -print -quit)
|
||||
if [ -n "$file" ]; then
|
||||
echo "Found $file for extension $ext"
|
||||
cp "$file" "upload/TriliumNextNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}.$ext"
|
||||
else
|
||||
echo "Warning: No file found with extension .$ext"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Final contents of upload directory:"
|
||||
ls -la upload/
|
||||
|
||||
7
.github/actions/build-server/action.yml
vendored
@ -1,4 +1,7 @@
|
||||
inputs:
|
||||
os:
|
||||
description: "One of the supported platforms: windows"
|
||||
required: true
|
||||
arch:
|
||||
description: "The architecture to build for: x64, arm64"
|
||||
required: true
|
||||
@ -18,11 +21,11 @@ runs:
|
||||
MATRIX_ARCH: ${{ inputs.arch }}
|
||||
shell: bash
|
||||
run: |
|
||||
npm run update-build-info
|
||||
npm run chore:update-build-info
|
||||
./bin/build-server.sh
|
||||
- name: Prepare artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p upload
|
||||
file=$(find dist -name '*.tar.xz' -print -quit)
|
||||
cp "$file" "upload/TriliumNextNotes-linux-${{ inputs.arch }}-${{ github.ref_name }}.tar.xz"
|
||||
cp "$file" "upload/TriliumNextNotes-Server-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}.tar.xz"
|
||||
|
||||
25
.github/workflows/main-docker.yml
vendored
@ -100,7 +100,20 @@ jobs:
|
||||
|
||||
build:
|
||||
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:
|
||||
- test_docker
|
||||
permissions:
|
||||
@ -108,16 +121,6 @@ jobs:
|
||||
packages: write
|
||||
attestations: 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:
|
||||
- name: Prepare
|
||||
run: |
|
||||
|
||||
48
.github/workflows/main.yml
vendored
@ -23,16 +23,46 @@ jobs:
|
||||
os:
|
||||
- name: macos
|
||||
image: macos-latest
|
||||
extension: dmg
|
||||
extension: [dmg, zip]
|
||||
- name: linux
|
||||
image: ubuntu-latest
|
||||
extension: deb
|
||||
extension: [deb, rpm, zip, flatpak]
|
||||
- name: windows
|
||||
image: windows-latest
|
||||
extension: exe
|
||||
extension: [exe, zip]
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Set up certificates and keychain for macOS
|
||||
- name: Install Apple Certificates
|
||||
if: matrix.os.name == 'macos'
|
||||
env:
|
||||
APP_CERTIFICATE_BASE64: ${{ secrets.APPLE_APP_CERTIFICATE_BASE64 }}
|
||||
APP_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_APP_CERTIFICATE_PASSWORD }}
|
||||
INSTALLER_CERTIFICATE_BASE64: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_BASE64 }}
|
||||
INSTALLER_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_PASSWORD }}
|
||||
KEYCHAIN_PASSWORD: ${{ github.run_id }}
|
||||
run: |
|
||||
# Create keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security set-keychain-settings -t 3600 -u build.keychain
|
||||
|
||||
# Import application certificate
|
||||
echo "$APP_CERTIFICATE_BASE64" | base64 --decode > application.p12
|
||||
security import application.p12 -k build.keychain -P "$APP_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
|
||||
rm application.p12
|
||||
|
||||
# Import installer certificate
|
||||
echo "$INSTALLER_CERTIFICATE_BASE64" | base64 --decode > installer.p12
|
||||
security import installer.p12 -k build.keychain -P "$INSTALLER_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
|
||||
rm installer.p12
|
||||
|
||||
# Update keychain settings
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
|
||||
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@ -43,6 +73,17 @@ jobs:
|
||||
os: ${{ matrix.os.name }}
|
||||
arch: ${{ matrix.arch }}
|
||||
extension: ${{ matrix.os.extension }}
|
||||
env:
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
|
||||
# Clean up keychain after build
|
||||
- name: Clean up keychain
|
||||
if: matrix.os.name == 'macos' && always()
|
||||
run: |
|
||||
security delete-keychain build.keychain
|
||||
|
||||
- name: Publish artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@ -53,6 +94,7 @@ jobs:
|
||||
with:
|
||||
name: TriliumNextNotes ${{ matrix.os.name }} ${{ matrix.arch }}.${{matrix.os.extension}}
|
||||
path: upload/*.${{ matrix.os.extension }}
|
||||
|
||||
build_linux_server:
|
||||
name: Build Linux Server
|
||||
strategy:
|
||||
|
||||
52
.github/workflows/nightly.yml
vendored
@ -20,13 +20,13 @@ jobs:
|
||||
os:
|
||||
- name: macos
|
||||
image: macos-latest
|
||||
extension: dmg
|
||||
extension: [dmg, zip]
|
||||
- name: linux
|
||||
image: ubuntu-latest
|
||||
extension: deb
|
||||
extension: [deb, rpm, zip, flatpak]
|
||||
- name: windows
|
||||
image: windows-latest
|
||||
extension: exe
|
||||
extension: [exe, zip]
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -38,32 +38,25 @@ jobs:
|
||||
shell: bash
|
||||
run: npm ci
|
||||
- name: Update nightly version
|
||||
run: npm run ci-update-nightly-version
|
||||
run: npm run chore:ci-update-nightly-version
|
||||
- name: Run the build
|
||||
uses: ./.github/actions/build-electron
|
||||
with:
|
||||
os: ${{ matrix.os.name }}
|
||||
arch: ${{ matrix.arch }}
|
||||
extension: ${{ matrix.os.extension }}
|
||||
- run: find output
|
||||
extension: ${{ join(matrix.os.extension, ' ') }}
|
||||
|
||||
- name: Deploy release
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
- name: Publish release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
upload_url: ${{ env.GITHUB_UPLOAD_URL }}
|
||||
release_id: ${{ env.GITHUB_RELEASE_ID }}
|
||||
asset_path: upload/TriliumNextNotes-${{ github.ref_name }}-${{ matrix.os.name }}-${{ matrix.arch }}.zip # path to archive to upload
|
||||
asset_name: TriliumNextNotes-${{ github.ref_name }}-${{ matrix.os.name }}-${{ matrix.arch }}-nightly.zip # name to upload the release as, use $$ to insert date (YYYYMMDD) and 6 letter commit hash
|
||||
asset_content_type: application/zip # required by GitHub API
|
||||
make_latest: false
|
||||
prerelease: true
|
||||
draft: false
|
||||
fail_on_unmatched_files: true
|
||||
files: upload/*.*
|
||||
tag_name: nightly
|
||||
name: Nightly Build
|
||||
|
||||
- name: Deploy installer release
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: ${{ env.GITHUB_UPLOAD_URL }}
|
||||
release_id: ${{ env.GITHUB_RELEASE_ID }}
|
||||
asset_path: upload/TriliumNextNotes-${{ github.ref_name }}-${{ matrix.os.name }}-${{ matrix.arch }}.${{ matrix.os.extension }} # path to archive to upload
|
||||
asset_name: TriliumNextNotes-${{ github.ref_name }}-${{ matrix.os.name }}-${{ matrix.arch }}-nightly.${{ matrix.os.extension }} # name to upload the release as, use $$ to insert date (YYYYMMDD) and 6 letter commit hash
|
||||
asset_content_type: application/zip # required by GitHub API
|
||||
nightly-server:
|
||||
name: Deploy server nightly
|
||||
strategy:
|
||||
@ -82,13 +75,16 @@ jobs:
|
||||
- name: Run the build
|
||||
uses: ./.github/actions/build-server
|
||||
with:
|
||||
os: linux
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
- name: Deploy release
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
- name: Publish release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
upload_url: ${{ env.GITHUB_UPLOAD_URL }}
|
||||
release_id: ${{ env.GITHUB_RELEASE_ID }}
|
||||
asset_path: upload/TriliumNextNotes-linux-${{ matrix.arch }}-${{ github.ref_name }}.tar.xz # path to archive to upload
|
||||
asset_name: TriliumNextNotes-linux-${{ matrix.arch }}-nightly.zip # name to upload the release as, use $$ to insert date (YYYYMMDD) and 6 letter commit hash
|
||||
asset_content_type: application/zip # required by GitHub API
|
||||
make_latest: false
|
||||
prerelease: true
|
||||
draft: false
|
||||
fail_on_unmatched_files: true
|
||||
files: upload/*.*
|
||||
tag_name: nightly
|
||||
name: Nightly Build
|
||||
|
||||
17
.github/workflows/release.yml
vendored
@ -23,10 +23,10 @@ jobs:
|
||||
extension: [dmg, zip]
|
||||
- name: linux
|
||||
image: ubuntu-latest
|
||||
extension: [deb, rpm, zip]
|
||||
extension: [deb, rpm, zip, flatpak]
|
||||
- name: windows
|
||||
image: windows-latest
|
||||
extension: exe
|
||||
extension: [exe, zip]
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -39,13 +39,23 @@ jobs:
|
||||
with:
|
||||
os: ${{ matrix.os.name }}
|
||||
arch: ${{ matrix.arch }}
|
||||
extension: ${{ matrix.os.extension }}
|
||||
extension: ${{ join(matrix.os.extension, ' ') }}
|
||||
env:
|
||||
APPLE_APP_CERTIFICATE_BASE64: ${{ secrets.APPLE_APP_CERTIFICATE_BASE64 }}
|
||||
APPLE_APP_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_APP_CERTIFICATE_PASSWORD }}
|
||||
APPLE_INSTALLER_CERTIFICATE_BASE64: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_BASE64 }}
|
||||
APPLE_INSTALLER_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
|
||||
- name: Publish release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: true
|
||||
fail_on_unmatched_files: true
|
||||
files: upload/*.*
|
||||
|
||||
build_linux_server-x64:
|
||||
name: Build Linux Server
|
||||
strategy:
|
||||
@ -64,6 +74,7 @@ jobs:
|
||||
- name: Run the build
|
||||
uses: ./.github/actions/build-server
|
||||
with:
|
||||
os: linux
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
- name: Publish release
|
||||
|
||||
2
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.cache
|
||||
.DS_Store
|
||||
node_modules/
|
||||
dist/
|
||||
@ -7,6 +8,7 @@ src/public/app-dist/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
po-*/
|
||||
.flatpak-builder/
|
||||
|
||||
*.db
|
||||
!integration-tests/db/document.db
|
||||
|
||||
@ -4,7 +4,7 @@ image:
|
||||
tasks:
|
||||
- before: nvm install 20.15.1 && nvm use 20.15.1
|
||||
init: npm install
|
||||
command: npm run start-server
|
||||
command: npm run server:start
|
||||
|
||||
ports:
|
||||
- port: 8080
|
||||
|
||||
4
.vscode/launch.json
vendored
@ -5,8 +5,8 @@
|
||||
{
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"name": "nodemon start-server",
|
||||
"program": "${workspaceFolder}/src/www",
|
||||
"name": "nodemon server:start",
|
||||
"program": "${workspaceFolder}/src/main",
|
||||
"request": "launch",
|
||||
"restart": true,
|
||||
"runtimeExecutable": "nodemon",
|
||||
|
||||
3
.vscode/settings.json
vendored
@ -18,5 +18,6 @@
|
||||
"github-actions.workflows.pinned.workflows": [".github/workflows/nightly.yml"],
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "vscode.css-language-features"
|
||||
}
|
||||
},
|
||||
"npm.exclude": ["**/build", "**/dist", "**/out/**"]
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
# Build stage
|
||||
FROM node:22.13.1-bullseye-slim AS builder
|
||||
FROM node:22.14.0-bullseye-slim AS builder
|
||||
|
||||
# Configure build dependencies in a single layer
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
@ -25,7 +25,7 @@ RUN cp -R build/src/* src/. && \
|
||||
cp build/docker_healthcheck.js . && \
|
||||
rm docker_healthcheck.ts && \
|
||||
npm install && \
|
||||
npm run webpack && \
|
||||
npm run build:webpack && \
|
||||
npm prune --omit=dev && \
|
||||
npm cache clean --force && \
|
||||
cp -r src/public/app/doc_notes src/public/app-dist/. && \
|
||||
@ -36,7 +36,7 @@ RUN cp -R build/src/* src/. && \
|
||||
rm -r build
|
||||
|
||||
# Runtime stage
|
||||
FROM node:22.13.1-bullseye-slim
|
||||
FROM node:22.14.0-bullseye-slim
|
||||
|
||||
# Install only runtime dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
# Build stage
|
||||
FROM node:22.13.1-alpine AS builder
|
||||
FROM node:22.14.0-alpine AS builder
|
||||
|
||||
# Configure build dependencies
|
||||
RUN apk add --no-cache --virtual .build-dependencies \
|
||||
@ -24,7 +24,7 @@ RUN cp -R build/src/* src/. && \
|
||||
cp build/docker_healthcheck.js . && \
|
||||
rm docker_healthcheck.ts && \
|
||||
npm install && \
|
||||
npm run webpack && \
|
||||
npm run build:webpack && \
|
||||
npm prune --omit=dev && \
|
||||
npm cache clean --force && \
|
||||
cp -r src/public/app/doc_notes src/public/app-dist/. && \
|
||||
@ -35,7 +35,7 @@ RUN cp -R build/src/* src/. && \
|
||||
rm -r build
|
||||
|
||||
# Runtime stage
|
||||
FROM node:22.13.1-alpine
|
||||
FROM node:22.14.0-alpine
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apk add --no-cache su-exec shadow
|
||||
|
||||
@ -78,7 +78,7 @@ Trilium 也提供 Flatpak:
|
||||
|
||||
```shell
|
||||
npm install
|
||||
npm run start-server
|
||||
npm run server:start
|
||||
```
|
||||
|
||||
## 👏 致谢
|
||||
|
||||
@ -86,7 +86,7 @@ Clone localmente y ejecute
|
||||
|
||||
```shell
|
||||
npm install
|
||||
npm run start-server
|
||||
npm run server:start
|
||||
```
|
||||
|
||||
## 👏 Reconocimientos
|
||||
|
||||
@ -73,7 +73,7 @@ Clona localmente ed esegui
|
||||
|
||||
```shell
|
||||
npm install
|
||||
npm run start-server
|
||||
npm run server:start
|
||||
```
|
||||
|
||||
## 👏 Riconoscimenti
|
||||
|
||||
@ -54,7 +54,7 @@ Trilium は Flatpak としても提供されます:
|
||||
|
||||
```shell
|
||||
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
|
||||
cd Notes
|
||||
npm install
|
||||
npm run start-server
|
||||
npm run server:start
|
||||
```
|
||||
|
||||
### Documentation
|
||||
@ -118,8 +118,10 @@ Head on over to our [Docs repo](https://github.com/TriliumNext/Docs)
|
||||
|
||||
## 🤝 Support
|
||||
|
||||
You can support the original Trilium developer using GitHub Sponsors, [PayPal](https://paypal.me/za4am) or Bitcoin (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2).
|
||||
Support for the TriliumNext organization will be possible in the near future.
|
||||
Support for the TriliumNext organization will be possible in the near future. For now, you can:
|
||||
- Support continued development on TriliumNext by supporting our developers: [eliandoran](https://github.com/sponsors/eliandoran) (See the [repository insights]([developers]([url](https://github.com/TriliumNext/Notes/graphs/contributors))) for a full list)
|
||||
- Show a token of gratitude to the original Trilium developer ([zadam](https://github.com/sponsors/zadam)) via [PayPal](https://paypal.me/za4am) or Bitcoin (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2).
|
||||
|
||||
|
||||
## 🔑 License
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ Trilium предоставляется в виде десктопного при
|
||||
|
||||
```shell
|
||||
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;
|
||||
|
||||
function log(...args) {
|
||||
function log(...args: any[]) {
|
||||
if (VERBOSE) {
|
||||
console.log(args);
|
||||
console.log(...args);
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +29,12 @@ const copy = async () => {
|
||||
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) {
|
||||
log(`Copying ${file}`);
|
||||
await fs.copy(file, path.join(DEST_DIR, file));
|
||||
@ -90,7 +95,6 @@ const copy = async () => {
|
||||
"node_modules/mark.js/dist/",
|
||||
"node_modules/normalize.css/",
|
||||
"node_modules/jquery.fancytree/dist/",
|
||||
"node_modules/bootstrap/dist/",
|
||||
"node_modules/autocomplete.js/dist/",
|
||||
"node_modules/codemirror/lib/",
|
||||
"node_modules/codemirror/addon/",
|
||||
|
||||
@ -23,7 +23,7 @@ rm -rf "$DIR"
|
||||
mkdir -pv "$DIR"
|
||||
|
||||
echo Webpack start
|
||||
npm run webpack
|
||||
npm run build:webpack
|
||||
echo Webpack finish
|
||||
|
||||
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
|
||||
|
||||
export GITHUB_REPO=trilium
|
||||
|
||||
if [[ $# -eq 0 ]] ; then
|
||||
echo "Missing argument of new version"
|
||||
exit 1
|
||||
@ -32,7 +30,7 @@ mv package.json.tmp package.json
|
||||
|
||||
git add package.json
|
||||
|
||||
npm run update-build-info
|
||||
npm run chore:update-build-info
|
||||
|
||||
git add src/services/build.ts
|
||||
|
||||
@ -40,10 +38,18 @@ TAG=v$VERSION
|
||||
|
||||
echo "Committing package.json version change"
|
||||
|
||||
git commit -m "release $VERSION"
|
||||
git commit -m "chore(release): $VERSION"
|
||||
git push
|
||||
|
||||
echo "Tagging commit with $TAG"
|
||||
|
||||
git tag $TAG
|
||||
git push origin $TAG
|
||||
|
||||
echo "Updating master"
|
||||
|
||||
git fetch
|
||||
git checkout master
|
||||
git reset --hard origin/master
|
||||
git merge origin/develop
|
||||
git push
|
||||
@ -28,6 +28,21 @@ keyPath=
|
||||
# expressjs shortcuts are supported: loopback(127.0.0.1/8, ::1/128), linklocal(169.254.0.0/16, fe80::/10), uniquelocal(10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7)
|
||||
trustedReverseProxy=false
|
||||
|
||||
|
||||
[Session]
|
||||
# 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).
|
||||
# It prevents your instances from overwriting each others' cookies, allowing you to stay logged in multiple instances simultanteously.
|
||||
# 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
|
||||
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]
|
||||
#syncServerHost=
|
||||
#syncServerTimeout=
|
||||
|
||||
BIN
db/demo.zip
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_revisions_blobId on revisions (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">
|
||||
<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'
|
||||
was compiled against a different Node.js version using
|
||||
NODE_MODULE_VERSION 108. This version of Node.js requires
|
||||
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>
|
||||
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
|
||||
@ -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="📝-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>
|
||||
<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>
|
||||
|
||||
<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
|
||||
npm install
|
||||
npm run start-server
|
||||
npm run server:start
|
||||
```
|
||||
|
||||
## 👏 致谢
|
||||
|
||||
@ -86,7 +86,7 @@ Clone localmente y ejecute
|
||||
|
||||
```shell
|
||||
npm install
|
||||
npm run start-server
|
||||
npm run server:start
|
||||
```
|
||||
|
||||
## 👏 Reconocimientos
|
||||
|
||||
@ -73,7 +73,7 @@ Clona localmente ed esegui
|
||||
|
||||
```shell
|
||||
npm install
|
||||
npm run start-server
|
||||
npm run server:start
|
||||
```
|
||||
|
||||
## 👏 Riconoscimenti
|
||||
|
||||
@ -54,7 +54,7 @@ Trilium は Flatpak としても提供されます:
|
||||
|
||||
```shell
|
||||
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
|
||||
cd Notes
|
||||
npm install
|
||||
npm run start-server
|
||||
npm run server:start
|
||||
```
|
||||
|
||||
### Documentation
|
||||
|
||||
@ -44,7 +44,7 @@ Trilium предоставляется в виде десктопного при
|
||||
|
||||
```shell
|
||||
npm install
|
||||
npm run start-server
|
||||
npm run server:start
|
||||
```
|
||||
|
||||
## 👏 Благодарности
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ test("Help popup", async ({ page, context }) => {
|
||||
await app.goto();
|
||||
|
||||
const popupPromise = page.waitForEvent("popup");
|
||||
await app.currentNoteSplit.press("F1");
|
||||
await app.currentNoteSplit.press("Shift+F1");
|
||||
await page.getByRole("link", { name: "online" }).click();
|
||||
const popup = await popupPromise;
|
||||
expect(popup.url()).toBe("https://triliumnext.github.io/Docs/");
|
||||
|
||||
10
entitlements.plist
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -3,6 +3,13 @@ const fs = require("fs-extra");
|
||||
|
||||
const APP_NAME = "TriliumNext Notes";
|
||||
|
||||
const extraResourcesForPlatform = getExtraResourcesForPlatform();
|
||||
const baseLinuxMakerConfigOptions = {
|
||||
icon: "./images/app-icons/png/128x128.png",
|
||||
desktopTemplate: path.resolve("./bin/electron-forge/desktop.ejs"),
|
||||
categories: ["Office", "Utility"]
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
packagerConfig: {
|
||||
executableName: "trilium",
|
||||
@ -10,38 +17,40 @@ module.exports = {
|
||||
overwrite: true,
|
||||
asar: true,
|
||||
icon: "./images/app-icons/icon",
|
||||
osxSign: {},
|
||||
osxNotarize: {
|
||||
appleId: process.env.APPLE_ID,
|
||||
appleIdPassword: process.env.APPLE_ID_PASSWORD,
|
||||
teamId: process.env.APPLE_TEAM_ID
|
||||
},
|
||||
extraResource: [
|
||||
// Moved to root
|
||||
...getExtraResourcesForPlatform(),
|
||||
// All resources should stay in Resources directory for macOS
|
||||
...(process.platform === "darwin" ? [] : extraResourcesForPlatform),
|
||||
|
||||
// Moved to resources (TriliumNext Notes.app/Contents/Resources on macOS)
|
||||
// These always go in Resources
|
||||
"translations/",
|
||||
"node_modules/@highlightjs/cdn-assets/styles"
|
||||
],
|
||||
afterComplete: [
|
||||
(buildPath, _electronVersion, platform, _arch, callback) => {
|
||||
const extraResources = getExtraResourcesForPlatform();
|
||||
for (const resource of extraResources) {
|
||||
// Only move resources on non-macOS platforms
|
||||
if (platform !== "darwin") {
|
||||
for (const resource of extraResourcesForPlatform) {
|
||||
const baseName = path.basename(resource);
|
||||
let sourcePath;
|
||||
if (platform === "darwin") {
|
||||
sourcePath = path.join(buildPath, `${APP_NAME}.app`, "Contents", "Resources", baseName);
|
||||
} else {
|
||||
sourcePath = path.join(buildPath, "resources", baseName);
|
||||
}
|
||||
let destPath;
|
||||
const sourcePath = path.join(buildPath, "resources", baseName);
|
||||
|
||||
if (baseName !== "256x256.png") {
|
||||
destPath = path.join(buildPath, baseName);
|
||||
} else {
|
||||
destPath = path.join(buildPath, "icon.png");
|
||||
}
|
||||
// prettier-ignore
|
||||
const destPath = (baseName !== "256x256.png")
|
||||
? path.join(buildPath, baseName)
|
||||
: path.join(buildPath, "icon.png");
|
||||
|
||||
// Copy files from resources folder to root
|
||||
fs.move(sourcePath, destPath)
|
||||
.then(() => callback())
|
||||
.catch((err) => callback(err));
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -53,17 +62,38 @@ module.exports = {
|
||||
name: "@electron-forge/maker-deb",
|
||||
config: {
|
||||
options: {
|
||||
icon: "./images/app-icons/png/128x128.png",
|
||||
desktopTemplate: path.resolve("./bin/electron-forge/desktop.ejs")
|
||||
...baseLinuxMakerConfigOptions
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "@electron-forge/maker-flatpak",
|
||||
config: {
|
||||
options: {
|
||||
...baseLinuxMakerConfigOptions,
|
||||
id: "com.triliumnext.notes",
|
||||
runtimeVersion: "24.08",
|
||||
base: "org.electronjs.Electron2.BaseApp",
|
||||
baseVersion: "24.08",
|
||||
baseFlatpakref: "https://flathub.org/repo/flathub.flatpakrepo",
|
||||
modules: [
|
||||
{
|
||||
name: "zypak",
|
||||
sources: {
|
||||
type: "git",
|
||||
url: "https://github.com/refi64/zypak",
|
||||
tag: "v2024.01.17"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "@electron-forge/maker-rpm",
|
||||
config: {
|
||||
options: {
|
||||
icon: "./images/app-icons/png/128x128.png",
|
||||
desktopTemplate: path.resolve("./bin/electron-forge/desktop.ejs")
|
||||
...baseLinuxMakerConfigOptions
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -100,21 +130,20 @@ module.exports = {
|
||||
};
|
||||
|
||||
function getExtraResourcesForPlatform() {
|
||||
let resources = ["dump-db/", "./bin/tpl/anonymize-database.sql"];
|
||||
const resources = ["dump-db/", "./bin/tpl/anonymize-database.sql"];
|
||||
|
||||
const getScriptRessources = () => {
|
||||
const scripts = ["trilium-portable", "trilium-safe-mode", "trilium-no-cert-check"];
|
||||
const scriptExt = (process.platform === "win32") ? "bat" : "sh";
|
||||
return scripts.map(script => `./bin/tpl/${script}.${scriptExt}`);
|
||||
}
|
||||
|
||||
switch (process.platform) {
|
||||
case "win32":
|
||||
for (const script of scripts) {
|
||||
resources.push(`./bin/tpl/${script}.bat`);
|
||||
}
|
||||
break;
|
||||
case "darwin":
|
||||
resources.push(...getScriptRessources())
|
||||
break;
|
||||
case "linux":
|
||||
resources.push("images/app-icons/png/256x256.png");
|
||||
for (const script of scripts) {
|
||||
resources.push(`./bin/tpl/${script}.sh`);
|
||||
}
|
||||
resources.push(...getScriptRessources(), "images/app-icons/png/256x256.png");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 109 KiB |
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 256 256" style="enable-background:new 0 0 256 256;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#686768;}
|
||||
@ -21,29 +21,29 @@
|
||||
.st15{fill:#EFB075;}
|
||||
.st16{fill:#E99547;}
|
||||
.st17{fill:#E47B19;}
|
||||
.st18{opacity:0.38;fill:url(#SVGID_5_);}
|
||||
.st18{opacity:0.38;fill:url(#SVGID_5_);enable-background:new ;}
|
||||
</style>
|
||||
<g id="Layer_1">
|
||||
<g id="Layer_1_2_">
|
||||
<g id="Layer_1_1_">
|
||||
</g>
|
||||
</g>
|
||||
<g id="Layer_2">
|
||||
<polygon class="st0" points="86.3,63.2 86.2,99.4 33.1,101.1 32.5,99.9 53.9,67.1 "/>
|
||||
<path class="st1" d="M86.3,61.9l-0.2,37.5c0,0-53.9,0.8-53.7,0.5l21.2-34L86.3,61.9z"/>
|
||||
<g id="Layer_2_1_">
|
||||
<polygon class="st0" points="69.5,48.6 69.3,93.1 4,95.2 3.3,93.7 29.6,53.4 "/>
|
||||
<path class="st1" d="M69.5,47l-0.2,46.1c0,0-66.3,1-66,0.6l26.1-41.8L69.5,47z"/>
|
||||
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="86.3479" y1="130.1949" x2="208.0555" y2="130.1949" gradientTransform="matrix(1 0 0 -1 0 258)">
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="69.458" y1="120.0202" x2="219.2576" y2="120.0202" gradientTransform="matrix(1 0 0 1 0 8)">
|
||||
<stop offset="0" style="stop-color:#E3E3E3"/>
|
||||
<stop offset="1" style="stop-color:#F4F4F4"/>
|
||||
</linearGradient>
|
||||
<polygon class="st2" points="86.3,61.9 207.8,68.9 208.1,188.4 86.7,193.7 "/>
|
||||
<polygon class="st2" points="69.5,47 218.9,55.6 219.3,202.6 69.9,209.1 "/>
|
||||
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="53.6067" y1="130.1949" x2="86.6402" y2="130.1949" gradientTransform="matrix(1 0 0 -1 0 258)">
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="29.2408" y1="120.0202" x2="69.8681" y2="120.0202" gradientTransform="matrix(1 0 0 1 0 8)">
|
||||
<stop offset="0" style="stop-color:#D9D9D9"/>
|
||||
<stop offset="1" style="stop-color:#D4D4D4"/>
|
||||
</linearGradient>
|
||||
<polygon class="st3" points="53.6,65.8 86.3,61.9 86.6,193.7 53.6,189.9 "/>
|
||||
<polygon class="st3" points="29.2,51.8 69.5,47 69.8,209.1 29.2,204.4 "/>
|
||||
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="154.1068" y1="201.7921" x2="146.7211" y2="271.9565" gradientTransform="matrix(0.9941 1.431752e-03 -1.431754e-03 -1.1143 -2.6949 323.3557)">
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="151.9309" y1="42.7213" x2="142.8473" y2="-43.5726" gradientTransform="matrix(0.9941 1.431752e-03 1.431754e-03 1.1143 -3.0394 44.4335)">
|
||||
<stop offset="0" style="stop-color:#B3B3B3"/>
|
||||
<stop offset="0.4752" style="stop-color:#B5B5B5"/>
|
||||
<stop offset="0.6464" style="stop-color:#BCBCBC"/>
|
||||
@ -52,64 +52,65 @@
|
||||
<stop offset="0.9506" style="stop-color:#EEEEEE"/>
|
||||
<stop offset="1" style="stop-color:#FFFFFF"/>
|
||||
</linearGradient>
|
||||
<polygon class="st4" points="208.1,103.8 109,99.5 86.3,62.2 207.8,68.9 "/>
|
||||
<polygon class="st1" points="112.8,93.1 234.1,99.3 235.4,97.8 88.5,63.5 86.3,61.9 "/>
|
||||
<polygon class="st5" points="235.4,97.8 133.9,92.5 112.8,91.1 86.6,62.2 208,68.9 219.8,81.8 235,97.4 235,97.4 "/>
|
||||
<polygon class="st4" points="219.3,98.5 97.4,93.2 69.5,47.3 218.9,55.6 "/>
|
||||
<polygon class="st1" points="102,85.3 251.2,93 252.8,91.1 72.2,48.9 69.5,47 "/>
|
||||
<polygon class="st5" points="252.8,91.1 128,84.6 102,82.9 69.8,47.3 219.1,55.6 233.6,71.4 252.3,90.6 252.3,90.6 "/>
|
||||
|
||||
<radialGradient id="SVGID_4_" cx="480.8341" cy="689.2393" r="3.2653" gradientTransform="matrix(0.5088 -4.329579e-03 -0.1464 -14.7395 -56.4799 10295.6123)" gradientUnits="userSpaceOnUse">
|
||||
<radialGradient id="SVGID_4_" cx="445.2994" cy="-436.338" r="4.0179" gradientTransform="matrix(0.5088 -4.329579e-03 0.1464 14.7395 -92.0455 6569.5317)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="6.758273e-02" style="stop-color:#FFFFFF;stop-opacity:0.9324"/>
|
||||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
|
||||
</radialGradient>
|
||||
<path class="st6" d="M88.5,147.7c0.2,21.3,0.7,34.5,0.1,34.5c-0.7,0-1.2-5.1-2-26.3c-0.9-21.2-1.1-69.1-0.4-69.2
|
||||
C86.8,86.5,88.3,126.5,88.5,147.7z"/>
|
||||
<path class="st6" d="M72.2,152.5c0.2,26.2,0.9,42.4,0.1,42.4c-0.9,0-1.5-6.3-2.5-32.3c-1.1-26.1-1.4-85-0.5-85.1
|
||||
C70.1,77.2,71.9,126.4,72.2,152.5z"/>
|
||||
<g class="st7">
|
||||
<path class="st8" d="M53.5,189.5l16.6,1.7c2.7,0.3,5.6,0.5,8.3,0.9l8.3,1h-0.1l60.7-2.6l30.4-1.4l7.6-0.3c2.5-0.1,5.1-0.2,7.6-0.3
|
||||
l15.2-0.4l-15.2,1c-2.5,0.2-5.1,0.3-7.6,0.4l-7.6,0.3l-30.4,1.4l-60.6,2.6l0,0l0,0l-8.3-1c-2.7-0.3-5.5-0.7-8.3-1.1L53.5,189.5z"
|
||||
/>
|
||||
<path class="st1" d="M53.1,189.5c2.7,0.2,5.5,0.3,8.4,0.5c2.9,0.2,5.8,0.4,8.6,0.7l8.3,0.9l8.3,1l-0.1,0.9l-0.1,0l0-0.9l60.8-2.5
|
||||
l30.4-1.3l15.2-0.6l15.2-0.4l0,0.5l-15.2,0.9l-7.6,0.4l-7.6,0.3l-30.4,1.3l-60.7,2.5l0,0l0,0l-8.3-1l-8.3-1.1l-16.6-2.2
|
||||
L53.1,189.5z M54.5,189.7l15.6,2l8.3,1.1l8.3,1l0,0l60.7-2.7l30.4-1.4l7.6-0.3l7.6-0.4l15.2-1l0,0.5l-15.2,0.4l-15.2,0.6
|
||||
l-30.4,1.4l-60.7,2.7l0-0.9l0.1,0l-0.1,0.9l-8.3-1l-8.3-0.9c-2.7-0.3-5.3-0.5-7.9-0.9C59.6,190.4,57.1,190,54.5,189.7z"/>
|
||||
<path class="st8" d="M29.1,203.9l20.4,2.1c3.3,0.4,6.9,0.6,10.2,1.1l10.2,1.2h-0.1l74.7-3.2l37.4-1.7l9.3-0.4
|
||||
c3.1-0.1,6.3-0.2,9.3-0.4l18.7-0.5l-18.7,1.2c-3.1,0.2-6.3,0.4-9.3,0.5l-9.3,0.4l-37.4,1.7l-74.5,3.2l0,0l0,0L59.7,208
|
||||
c-3.3-0.4-6.8-0.9-10.2-1.4L29.1,203.9z"/>
|
||||
<path class="st1" d="M28.6,203.9c3.3,0.2,6.8,0.4,10.3,0.6s7.1,0.5,10.6,0.9l10.2,1.1l10.2,1.2l-0.1,1.1h-0.1v-1.1l74.8-3.1
|
||||
l37.4-1.6l18.7-0.7l18.7-0.5v0.6l-18.7,1.1l-9.3,0.5l-9.3,0.4l-37.4,1.6l-74.7,3.1l0,0l0,0l-10.2-1.2l-10.2-1.4L29,203.8
|
||||
L28.6,203.9z M30.3,204.1l19.2,2.5l10.2,1.4l10.2,1.2l0,0l74.7-3.3l37.4-1.7l9.3-0.4l9.3-0.5l18.7-1.2v0.6l-18.7,0.5l-18.7,0.7
|
||||
l-37.4,1.7l-74.7,3.3v-1.1h0.1l-0.1,1.1l-10.2-1.2l-10.2-1.1c-3.3-0.4-6.5-0.6-9.7-1.1C36.6,205,33.5,204.5,30.3,204.1z"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st9" d="M177.3,134.6c-7.1,5.5-19.1,6.6-27.5,4.5c2.1-1.9,3.1-2.8,5.1-4.7c2-1.8,2.9-2.6,4.9-4.4
|
||||
c6.8-6,10.2-8.8,16.8-14.4c-6.9,5.2-10.5,7.8-17.6,13.3c-2,1.6-3,2.3-5,3.9c-2.1,1.6-3.1,2.5-5.2,4.1c-0.4-7.7,0.9-18,8.4-23.5
|
||||
c0.6-0.5,1.4-0.9,2.1-1.4c1-0.5,2-1.1,3.2-1.5c9.3-3.6,20.2-6.1,30.3-4.8c0.6,5.3-4,15.4-9.6,22.9c-0.8,1-1.5,2-2.3,2.9
|
||||
C179.6,132.6,178.4,133.7,177.3,134.6z"/>
|
||||
<path class="st10" d="M180.7,131.4c-7.5,4.9-18.4,4.7-25.8,3c2-1.8,2.9-2.6,4.9-4.4c6.8-6,10.2-8.8,16.8-14.4
|
||||
c-6.9,5.2-10.5,7.8-17.6,13.3c-2,1.6-3,2.3-5,3.9c-0.4-6.4,0.3-15,5.3-20.7c1-0.5,2-1.1,3.2-1.5c9.3-3.7,20.2-6.1,30.3-4.8
|
||||
c0.6,5.3-4,15.4-9.6,22.9C182.3,129.5,181.5,130.5,180.7,131.4z"/>
|
||||
<path class="st11" d="M183.1,128.5c-7.2,3.4-16.7,3.1-23.2,1.5c6.8-6,10.2-8.8,16.8-14.4c-6.9,5.2-10.5,7.8-17.6,13.3
|
||||
c-0.4-5.5,0-12.8,3.5-18.4c9.3-3.6,20.2-6.1,30.3-4.8C193.4,111,188.8,121.2,183.1,128.5z"/>
|
||||
<path class="st9" d="M181.4,136.4c-8.7,6.8-23.5,8.1-33.8,5.5c2.6-2.3,3.8-3.4,6.3-5.8c2.5-2.2,3.6-3.2,6-5.4
|
||||
c8.4-7.4,12.5-10.8,20.7-17.7c-8.5,6.4-12.9,9.6-21.6,16.4c-2.5,2-3.7,2.8-6.1,4.8c-2.6,2-3.8,3.1-6.4,5
|
||||
c-0.5-9.5,1.1-22.1,10.3-28.9c0.7-0.6,1.7-1.1,2.6-1.7c1.2-0.6,2.5-1.4,3.9-1.8c11.4-4.4,24.8-7.5,37.3-5.9
|
||||
c0.7,6.5-4.9,18.9-11.8,28.2c-1,1.2-1.8,2.5-2.8,3.6C184.2,133.9,182.7,135.3,181.4,136.4z"/>
|
||||
<path class="st10" d="M185.6,132.4c-9.2,6-22.6,5.8-31.7,3.7c2.5-2.2,3.6-3.2,6-5.4c8.4-7.4,12.5-10.8,20.7-17.7
|
||||
c-8.5,6.4-12.9,9.6-21.6,16.4c-2.5,2-3.7,2.8-6.1,4.8c-0.5-7.9,0.4-18.4,6.5-25.5c1.2-0.6,2.5-1.4,3.9-1.8
|
||||
c11.4-4.6,24.8-7.5,37.3-5.9c0.7,6.5-4.9,18.9-11.8,28.2C187.5,130.1,186.5,131.3,185.6,132.4z"/>
|
||||
<path class="st11" d="M188.5,128.9c-8.9,4.2-20.5,3.8-28.5,1.8c8.4-7.4,12.5-10.8,20.7-17.7c-8.5,6.4-12.9,9.6-21.6,16.4
|
||||
c-0.5-6.8,0-15.7,4.3-22.6c11.4-4.4,24.8-7.5,37.3-5.9C201.2,107.4,195.5,119.9,188.5,128.9z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st12" d="M144,161.3c-2.9-7.2,0.4-15.9,3.8-21.1c0.9,2,1.3,3,2.2,4.9c0.9,1.9,1.3,2.8,2.1,4.6
|
||||
c3,6.4,4.5,9.6,7.6,15.6c-2.5-6.2-3.8-9.4-6.4-16c-0.7-1.8-1.1-2.7-1.8-4.5c-0.8-1.9-1.2-2.9-1.9-4.9c6,1.8,13.7,5.4,16.5,12.2
|
||||
c0.2,0.6,0.4,1.2,0.6,1.8c0.2,0.8,0.4,1.7,0.5,2.6c1.2,7.8-0.7,18.7-3.6,22.8c-4.5-0.7-11.8-6.3-16.3-12.3
|
||||
c-0.6-0.8-1.2-1.6-1.7-2.4C145,163.5,144.5,162.4,144,161.3z"/>
|
||||
<path class="st13" d="M145.7,164.6c-1.9-6.8,1.2-14.7,4.4-19.5c0.9,1.9,1.3,2.8,2.1,4.6c3,6.4,4.5,9.6,7.6,15.6
|
||||
c-2.5-6.2-3.8-9.4-6.4-16c-0.7-1.8-1.1-2.7-1.8-4.5c5.1,1.4,11.7,4.2,15.2,9.2c0.2,0.8,0.4,1.7,0.5,2.6
|
||||
c1.2,7.8-0.7,18.7-3.6,22.7c-4.5-0.7-11.8-6.3-16.3-12.3C146.8,166.2,146.3,165.4,145.7,164.6z"/>
|
||||
<path class="st14" d="M147.4,167c-0.9-6.1,2-13,4.8-17.3c3,6.4,4.5,9.6,7.6,15.6c-2.5-6.2-3.8-9.4-6.4-16
|
||||
c4.5,1.1,10.2,3.3,14,7.2c1.2,7.8-0.7,18.7-3.6,22.7C159.1,178.5,151.9,173,147.4,167z"/>
|
||||
<path class="st12" d="M140.4,169.2c-3.6-8.9,0.5-19.6,4.7-26c1.1,2.5,1.6,3.7,2.7,6c1.1,2.3,1.6,3.4,2.6,5.7
|
||||
c3.7,7.9,5.5,11.8,9.3,19.2c-3.1-7.6-4.7-11.6-7.9-19.7c-0.9-2.2-1.4-3.3-2.2-5.5c-1-2.3-1.5-3.6-2.3-6
|
||||
c7.4,2.2,16.8,6.6,20.3,15c0.2,0.7,0.5,1.5,0.7,2.2c0.2,1,0.5,2.1,0.6,3.2c1.5,9.6-0.9,23-4.4,28c-5.5-0.9-14.5-7.7-20-15.1
|
||||
c-0.7-1-1.5-2-2.1-3C141.7,171.9,141,170.6,140.4,169.2z"/>
|
||||
<path class="st13" d="M142.5,173.3c-2.3-8.4,1.5-18.1,5.4-24c1.1,2.3,1.6,3.4,2.6,5.7c3.7,7.9,5.5,11.8,9.3,19.2
|
||||
c-3.1-7.6-4.7-11.6-7.9-19.7c-0.9-2.2-1.4-3.3-2.2-5.5c6.3,1.7,14.4,5.2,18.7,11.3c0.2,1,0.5,2.1,0.6,3.2
|
||||
c1.5,9.6-0.9,23-4.4,27.9c-5.5-0.9-14.5-7.7-20-15.1C143.9,175.2,143.3,174.3,142.5,173.3z"/>
|
||||
<path class="st14" d="M144.6,176.2c-1.1-7.5,2.5-16,5.9-21.3c3.7,7.9,5.5,11.8,9.3,19.2c-3.1-7.6-4.7-11.6-7.9-19.7
|
||||
c5.5,1.4,12.5,4.1,17.2,8.9c1.5,9.6-0.9,23-4.4,27.9C159,190.4,150.1,183.6,144.6,176.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st15" d="M132.2,118.5c8.5,3.5,13.4,12.5,15.3,19c-2.4-0.8-3.5-1.1-5.9-1.9c-2.3-0.7-3.4-1.1-5.6-1.8
|
||||
c-7.9-2.6-11.8-4-19.4-6.7c7.4,3.1,11.1,4.7,18.8,7.8c2.1,0.9,3.2,1.3,5.3,2.2c2.2,0.9,3.3,1.3,5.6,2.2c-6,3.4-15,6.8-23,3.7
|
||||
c-0.6-0.2-1.4-0.6-2.1-1c-0.8-0.5-1.8-1-2.7-1.7c-6.9-4.9-14.3-13.6-17-21.8c4-2.8,14.3-3.4,23-1.9c1.2,0.2,2.3,0.4,3.5,0.7
|
||||
C129.6,117.5,130.9,117.9,132.2,118.5z"/>
|
||||
<path class="st16" d="M128,117.1c7.4,3.9,11.8,12.2,13.6,18.4c-2.3-0.7-3.4-1.1-5.6-1.8c-7.9-2.6-11.8-4-19.4-6.7
|
||||
c7.4,3.1,11.1,4.7,18.7,7.8c2.1,0.9,3.2,1.3,5.3,2.2c-5,2.9-12.5,6-19.4,4.9c-0.8-0.5-1.8-1-2.7-1.7c-6.9-4.9-14.3-13.6-17-21.8
|
||||
c4-2.8,14.3-3.4,23-1.9C125.8,116.6,126.9,116.7,128,117.1z"/>
|
||||
<path class="st17" d="M124.6,116.3c6.1,4.3,9.8,11.7,11.4,17.3c-7.9-2.6-11.8-4-19.4-6.7c7.4,3.1,11.1,4.7,18.8,7.8
|
||||
c-4.4,2.6-10.6,5.4-16.8,5.3c-6.9-4.9-14.3-13.6-17-21.8C105.6,115.4,115.8,114.8,124.6,116.3z"/>
|
||||
<path class="st15" d="M125.9,116.6c10.5,4.3,16.5,15.4,18.8,23.4c-3-1-4.3-1.4-7.3-2.3c-2.8-0.9-4.2-1.4-6.9-2.2
|
||||
c-9.7-3.2-14.5-4.9-23.9-8.2c9.1,3.8,13.7,5.8,23.1,9.6c2.6,1.1,3.9,1.6,6.5,2.7c2.7,1.1,4.1,1.6,6.9,2.7
|
||||
c-7.4,4.2-18.4,8.4-28.3,4.6c-0.7-0.2-1.7-0.7-2.6-1.2c-1-0.6-2.2-1.2-3.3-2.1c-8.5-6-17.6-16.7-20.9-26.8
|
||||
c4.9-3.4,17.6-4.2,28.3-2.3c1.5,0.2,2.8,0.5,4.3,0.9C122.7,115.4,124.3,115.8,125.9,116.6z"/>
|
||||
<path class="st16" d="M120.7,114.9c9.1,4.8,14.5,15,16.7,22.6c-2.8-0.9-4.2-1.4-6.9-2.2c-9.7-3.2-14.5-4.9-23.9-8.2
|
||||
c9.1,3.8,13.7,5.8,23,9.6c2.6,1.1,3.9,1.6,6.5,2.7c-6.1,3.6-15.4,7.4-23.9,6c-1-0.6-2.2-1.2-3.3-2.1c-8.5-6-17.6-16.7-20.9-26.8
|
||||
c4.9-3.4,17.6-4.2,28.3-2.3C118,114.2,119.4,114.4,120.7,114.9z"/>
|
||||
<path class="st17" d="M116.6,113.9c7.5,5.3,12.1,14.4,14,21.3c-9.7-3.2-14.5-4.9-23.9-8.2c9.1,3.8,13.7,5.8,23.1,9.6
|
||||
c-5.4,3.2-13,6.6-20.7,6.5c-8.5-6-17.6-16.7-20.9-26.8C93.2,112.8,105.7,112,116.6,113.9z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="226.3925" y1="147.1083" x2="159.9567" y2="186.9981">
|
||||
|
||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="241.7537" y1="104.2354" x2="160.0455" y2="55.1756" gradientTransform="matrix(1 0 0 -1 0 256)">
|
||||
<stop offset="0.1721" style="stop-color:#C7C7C7"/>
|
||||
<stop offset="0.3798" style="stop-color:#D8D8D8"/>
|
||||
<stop offset="0.6814" style="stop-color:#DADADA"/>
|
||||
@ -118,7 +119,7 @@
|
||||
<stop offset="0.8745" style="stop-color:#EEEEEE"/>
|
||||
<stop offset="1" style="stop-color:#FFFFFF"/>
|
||||
</linearGradient>
|
||||
<path class="st18" d="M208,128c-0.8,0.3-2.7,12.8-3,15.6c-0.6,4.7-3.2,23.3-9,33.5c-5.9,10.4-12.8,11.1-13.3,11.9l25.3-0.7
|
||||
C208,169.3,208,146.9,208,128L208,128z"/>
|
||||
<path class="st18" d="M219.1,128.3c-1,0.4-3.3,15.7-3.7,19.2c-0.7,5.8-3.9,28.7-11.1,41.2c-7.3,12.8-15.7,13.7-16.4,14.6l31.1-0.9
|
||||
C219.1,179.1,219.1,151.5,219.1,128.3L219.1,128.3z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.6 KiB |
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 " ],
|
||||
mime: "text/x-hcl",
|
||||
mode: "hcl",
|
||||
name: "Terraform (HCL)"
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
2668
package-lock.json
generated
137
package.json
@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "TriliumNext Notes",
|
||||
"description": "Build your personal knowledge base with TriliumNext Notes",
|
||||
"version": "0.91.5",
|
||||
"version": "0.92.2-beta",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "./dist/electron-main.js",
|
||||
"author": {
|
||||
@ -20,61 +20,68 @@
|
||||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start-server": "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",
|
||||
"start-server-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",
|
||||
"qstart-server": "npm run switch-server && npm run start-server",
|
||||
"start-electron": "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 .",
|
||||
"start-electron-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 .\"",
|
||||
"start-electron-no-dir": "npm run prepare-dist && cross-env TRILIUM_ENV=dev electron --inspect=5858 .",
|
||||
"start-electron-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 .\"",
|
||||
"qstart-electron": "npm run switch-electron && npm run start-electron",
|
||||
"switch-server": "rimraf ./node_modules/better-sqlite3 && npm install",
|
||||
"switch-electron": "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",
|
||||
"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",
|
||||
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs",
|
||||
"webpack": "tsx node_modules/webpack/bin/webpack.js -c webpack.config.ts",
|
||||
"test-playwright": "playwright test",
|
||||
"test": "cross-env TRILIUM_DATA_DIR=./data-test vitest",
|
||||
"test-coverage": "cross-env TRILIUM_DATA_DIR=./data-test vitest --coverage",
|
||||
"start-electron-forge": "npm run prepare-dist && electron-forge start",
|
||||
"make-electron": "npm run webpack && npm run prepare-dist && electron-forge make",
|
||||
"package-electron": "electron-forge package",
|
||||
"prepare-dist": "rimraf ./dist && tsc && tsx ./bin/copy-dist.ts",
|
||||
"watch-dist": "tsx ./bin/watch-dist.ts",
|
||||
"update-build-info": "tsx bin/update-build-info.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",
|
||||
"integration-mem-db": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.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",
|
||||
"generate-document": "cross-env nodemon ./bin/generate_document.ts 1000",
|
||||
"ci-update-nightly-version": "tsx ./bin/update-nightly-version.ts",
|
||||
"prettier-check": "prettier . --check",
|
||||
"prettier-fix": "prettier . --write"
|
||||
"server:start": "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",
|
||||
"server:start-no-dir": "cross-env TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 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",
|
||||
"server:qstart": "npm run server:switch && npm run server:start",
|
||||
"server:switch": "rimraf ./node_modules/better-sqlite3 && npm install",
|
||||
"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 .",
|
||||
"electron:start-no-dir": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_ENV=dev electron --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 .\"",
|
||||
"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 .\"",
|
||||
"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 .",
|
||||
"electron:start-prod-no-dir": "npm run build:prepare-dist && cross-env TRILIUM_ENV=dev electron --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 .\"",
|
||||
"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 .\"",
|
||||
"electron:qstart": "npm run electron:switch && npm run electron:start",
|
||||
"electron:switch": "electron-rebuild",
|
||||
"electron-forge:start": "npm run build:prepare-dist && electron-forge start",
|
||||
"electron-forge:make": "npm run build:prepare-dist && electron-forge make",
|
||||
"electron-forge:package": "npm run build:prepare-dist && electron-forge package",
|
||||
"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",
|
||||
"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",
|
||||
"docs:build": "npm run docs:build-backend && npm run docs:build-frontend",
|
||||
"build:webpack": "tsx node_modules/webpack/bin/webpack.js -c webpack.config.ts",
|
||||
"build:prepare-dist": "npm run build:webpack && rimraf ./dist && tsc && tsx ./bin/copy-dist.ts",
|
||||
"test": "cross-env TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest",
|
||||
"test:coverage": "cross-env TRILIUM_DATA_DIR=./integration-tests/db vitest --coverage",
|
||||
"test:playwright": "playwright test",
|
||||
"test:integration-edit-db": "cross-env TRILIUM_INTEGRATION_TEST=edit TRILIUM_PORT=8081 TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
|
||||
"test:integration-mem-db": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 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",
|
||||
"dev:watch-dist": "tsx ./bin/watch-dist.ts",
|
||||
"dev:prettier-check": "prettier . --check",
|
||||
"dev:prettier-fix": "prettier . --write",
|
||||
"chore:update-build-info": "tsx bin/update-build-info.ts",
|
||||
"chore:ci-update-nightly-version": "tsx ./bin/update-nightly-version.ts",
|
||||
"chore:generate-document": "cross-env nodemon ./bin/generate_document.ts 1000",
|
||||
"chore:generate-openapi": "tsx bin/generate-openapi.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "7.1.1",
|
||||
"@electron/remote": "2.1.2",
|
||||
"@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",
|
||||
"@joplin/turndown-plugin-gfm": "1.0.61",
|
||||
"@mermaid-js/layout-elk": "0.1.7",
|
||||
"@mind-elixir/node-menu": "1.0.4",
|
||||
"@triliumnext/express-partial-content": "1.0.1",
|
||||
"@types/leaflet": "1.9.16",
|
||||
"@types/react-dom": "18.3.5",
|
||||
"archiver": "7.0.1",
|
||||
"async-mutex": "0.5.0",
|
||||
"autocomplete.js": "0.38.1",
|
||||
"axios": "1.7.9",
|
||||
"better-sqlite3": "11.8.1",
|
||||
"bootstrap": "5.3.3",
|
||||
"boxicons": "2.1.4",
|
||||
"chardet": "2.0.0",
|
||||
"cheerio": "1.0.0",
|
||||
"chokidar": "4.0.3",
|
||||
"cls-hooked": "4.2.2",
|
||||
"codemirror": "5.65.18",
|
||||
"compression": "1.7.5",
|
||||
"compression": "1.8.0",
|
||||
"cookie-parser": "1.4.7",
|
||||
"csrf-csrf": "3.1.0",
|
||||
"dayjs": "1.11.13",
|
||||
@ -105,10 +112,10 @@
|
||||
"is-animated": "2.0.2",
|
||||
"is-svg": "5.1.0",
|
||||
"jimp": "1.6.0",
|
||||
"joplin-turndown-plugin-gfm": "1.0.12",
|
||||
"jquery": "3.7.1",
|
||||
"jquery-hotkeys": "0.2.2",
|
||||
"jquery.fancytree": "2.38.4",
|
||||
"js-yaml": "4.1.0",
|
||||
"jsdom": "26.0.0",
|
||||
"jsplumb": "2.15.6",
|
||||
"katex": "0.16.21",
|
||||
@ -116,10 +123,10 @@
|
||||
"leaflet": "1.9.4",
|
||||
"leaflet-gpx": "2.1.2",
|
||||
"mark.js": "8.11.1",
|
||||
"marked": "15.0.6",
|
||||
"marked": "15.0.7",
|
||||
"mermaid": "11.4.1",
|
||||
"mime-types": "2.1.35",
|
||||
"mind-elixir": "4.3.6",
|
||||
"mind-elixir": "4.3.7",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"normalize-strings": "1.1.1",
|
||||
"normalize.css": "8.0.1",
|
||||
@ -136,26 +143,30 @@
|
||||
"source-map-support": "0.5.21",
|
||||
"split.js": "1.6.5",
|
||||
"stream-throttle": "0.1.3",
|
||||
"strip-bom": "5.0.0",
|
||||
"striptags": "3.2.0",
|
||||
"swagger-ui-express": "5.0.1",
|
||||
"tmp": "0.2.3",
|
||||
"ts-loader": "9.5.2",
|
||||
"turndown": "7.2.0",
|
||||
"unescape": "1.0.1",
|
||||
"vanilla-js-wheel-zoom": "9.0.4",
|
||||
"ws": "8.18.0",
|
||||
"ws": "8.18.1",
|
||||
"xml2js": "0.6.2",
|
||||
"yauzl": "3.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "7.6.1",
|
||||
"@electron-forge/maker-deb": "7.6.1",
|
||||
"@electron-forge/maker-dmg": "7.6.1",
|
||||
"@electron-forge/maker-rpm": "7.6.1",
|
||||
"@electron-forge/maker-squirrel": "7.6.1",
|
||||
"@electron-forge/maker-zip": "7.6.1",
|
||||
"@electron-forge/plugin-auto-unpack-natives": "7.6.1",
|
||||
"@electron-forge/cli": "7.7.0",
|
||||
"@electron-forge/maker-deb": "7.7.0",
|
||||
"@electron-forge/maker-dmg": "7.7.0",
|
||||
"@electron-forge/maker-flatpak": "7.7.0",
|
||||
"@electron-forge/maker-rpm": "7.7.0",
|
||||
"@electron-forge/maker-squirrel": "7.7.0",
|
||||
"@electron-forge/maker-zip": "7.7.0",
|
||||
"@electron-forge/plugin-auto-unpack-natives": "7.7.0",
|
||||
"@electron/rebuild": "3.7.1",
|
||||
"@playwright/test": "1.50.1",
|
||||
"@popperjs/core": "2.11.8",
|
||||
"@types/archiver": "6.0.3",
|
||||
"@types/better-sqlite3": "7.6.12",
|
||||
"@types/bootstrap": "5.2.10",
|
||||
@ -172,14 +183,16 @@
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/html": "1.0.4",
|
||||
"@types/ini": "4.1.1",
|
||||
"@types/jasmine": "5.1.5",
|
||||
"@types/jquery": "3.5.32",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/jsdom": "21.1.7",
|
||||
"@types/leaflet": "1.9.16",
|
||||
"@types/leaflet-gpx": "1.3.7",
|
||||
"@types/mime-types": "2.1.4",
|
||||
"@types/multer": "1.4.12",
|
||||
"@types/node": "22.13.1",
|
||||
"@types/node": "22.13.5",
|
||||
"@types/react": "18.3.18",
|
||||
"@types/react-dom": "18.3.5",
|
||||
"@types/safe-compare": "1.1.2",
|
||||
"@types/sanitize-html": "2.13.0",
|
||||
"@types/sax": "1.2.7",
|
||||
@ -187,28 +200,36 @@
|
||||
"@types/session-file-store": "1.2.5",
|
||||
"@types/source-map-support": "0.5.10",
|
||||
"@types/stream-throttle": "0.1.4",
|
||||
"@types/swagger-ui-express": "4.1.8",
|
||||
"@types/tmp": "0.2.6",
|
||||
"@types/turndown": "5.0.5",
|
||||
"@types/ws": "8.5.14",
|
||||
"@types/xml2js": "0.4.14",
|
||||
"@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",
|
||||
"electron": "34.0.2",
|
||||
"css-loader": "7.1.2",
|
||||
"electron": "34.2.0",
|
||||
"esm": "3.2.25",
|
||||
"jasmine": "5.5.0",
|
||||
"jsdoc": "4.0.4",
|
||||
"lorem-ipsum": "2.0.8",
|
||||
"mini-css-extract-plugin": "2.9.2",
|
||||
"nodemon": "3.1.9",
|
||||
"prettier": "3.4.2",
|
||||
"postcss-loader": "8.1.1",
|
||||
"prettier": "3.5.2",
|
||||
"rcedit": "4.0.1",
|
||||
"rimraf": "6.0.1",
|
||||
"sass": "1.85.0",
|
||||
"sass-loader": "16.0.5",
|
||||
"swagger-jsdoc": "6.2.8",
|
||||
"tslib": "2.8.1",
|
||||
"tsx": "4.19.2",
|
||||
"typedoc": "0.27.6",
|
||||
"tsx": "4.19.3",
|
||||
"typedoc": "0.27.8",
|
||||
"typescript": "5.7.3",
|
||||
"vitest": "3.0.5",
|
||||
"webpack": "5.97.1",
|
||||
"vitest": "3.0.6",
|
||||
"webpack": "5.98.0",
|
||||
"webpack-cli": "6.0.1",
|
||||
"webpack-dev-middleware": "7.4.2"
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ export default defineConfig({
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
webServer: !process.env.TRILIUM_DOCKER ? {
|
||||
command: 'npm run integration-mem-db-dev',
|
||||
command: 'npm run test:integration-mem-db-dev',
|
||||
url: SERVER_URL,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
} : undefined,
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import etapi from "../support/etapi.js";
|
||||
|
||||
/* TriliumNextTODO: port to Vitest
|
||||
etapi.describeEtapi("app_info", () => {
|
||||
it("get", async () => {
|
||||
const appInfo = await etapi.getEtapi("app-info");
|
||||
expect(appInfo.clipperProtocolVersion).toEqual("1.0");
|
||||
});
|
||||
});
|
||||
*/
|
||||
@ -1,8 +1,10 @@
|
||||
import etapi from "../support/etapi.js";
|
||||
|
||||
/* TriliumNextTODO: port to Vitest
|
||||
etapi.describeEtapi("backup", () => {
|
||||
it("create", async () => {
|
||||
const response = await etapi.putEtapiContent("backup/etapi_test");
|
||||
expect(response.status).toEqual(204);
|
||||
});
|
||||
});
|
||||
*/
|
||||
@ -3,6 +3,7 @@ import fs from "fs";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
/* TriliumNextTODO: port to Vitest
|
||||
etapi.describeEtapi("import", () => {
|
||||
// temporarily skip this test since test-export.zip is missing
|
||||
xit("import", async () => {
|
||||
@ -22,3 +23,4 @@ etapi.describeEtapi("import", () => {
|
||||
expect(content).toContain("test export content");
|
||||
});
|
||||
});
|
||||
*/
|
||||
@ -1,6 +1,7 @@
|
||||
import crypto from "crypto";
|
||||
import etapi from "../support/etapi.js";
|
||||
|
||||
/* TriliumNextTODO: port to Vitest
|
||||
etapi.describeEtapi("notes", () => {
|
||||
it("create", async () => {
|
||||
const { note, branch } = await etapi.postEtapi("create-note", {
|
||||
@ -99,3 +100,4 @@ etapi.describeEtapi("notes", () => {
|
||||
expect(error.message).toEqual(`Note '${note.noteId}' not found.`);
|
||||
});
|
||||
});
|
||||
*/
|
||||
@ -4,14 +4,14 @@ import BAttribute from "../../src/becca/entities/battribute.js";
|
||||
import becca from "../../src/becca/becca.js";
|
||||
import randtoken from "rand-token";
|
||||
import type SearchResult from "../../src/services/search/search_result.js";
|
||||
import type { NoteType } from "../../src/becca/entities/rows.js";
|
||||
import type { NoteRow, NoteType } from "../../src/becca/entities/rows.js";
|
||||
randtoken.generator({ source: "crypto" });
|
||||
|
||||
function findNoteByTitle(searchResults: Array<SearchResult>, title: string): BNote | undefined {
|
||||
export function findNoteByTitle(searchResults: Array<SearchResult>, title: string): BNote | undefined {
|
||||
return searchResults.map((sr) => becca.notes[sr.noteId]).find((note) => note.title === title);
|
||||
}
|
||||
|
||||
class NoteBuilder {
|
||||
export class NoteBuilder {
|
||||
note: BNote;
|
||||
constructor(note: BNote) {
|
||||
this.note = note;
|
||||
@ -55,11 +55,11 @@ class NoteBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
function id() {
|
||||
export function id() {
|
||||
return randtoken.generate(10);
|
||||
}
|
||||
|
||||
function note(title: string, extraParams = {}) {
|
||||
export function note(title: string, extraParams: Partial<NoteRow> = {}) {
|
||||
const row = Object.assign(
|
||||
{
|
||||
noteId: id(),
|
||||
@ -74,9 +74,3 @@ function note(title: string, extraParams = {}) {
|
||||
|
||||
return new NoteBuilder(note);
|
||||
}
|
||||
|
||||
export default {
|
||||
NoteBuilder,
|
||||
findNoteByTitle,
|
||||
note
|
||||
};
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import type child_process from "child_process";
|
||||
import { describe, beforeAll, afterAll } from "vitest";
|
||||
|
||||
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) {
|
||||
const str = strings.toString();
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import type { AttachmentRow, BlobRow, RevisionRow } from "./entities/rows.js";
|
||||
import BBlob from "./entities/bblob.js";
|
||||
import BRecentNote from "./entities/brecent_note.js";
|
||||
import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js";
|
||||
import type BTask from "./entities/btask.js";
|
||||
|
||||
interface AttachmentOpts {
|
||||
includeContentLength?: boolean;
|
||||
@ -32,6 +33,7 @@ export default class Becca {
|
||||
attributeIndex!: Record<string, BAttribute[]>;
|
||||
options!: Record<string, BOption>;
|
||||
etapiTokens!: Record<string, BEtapiToken>;
|
||||
tasks!: Record<string, BTask>;
|
||||
|
||||
allNoteSetCache: NoteSet | null;
|
||||
|
||||
@ -48,6 +50,7 @@ export default class Becca {
|
||||
this.attributeIndex = {};
|
||||
this.options = {};
|
||||
this.etapiTokens = {};
|
||||
this.tasks = {};
|
||||
|
||||
this.dirtyNoteSetCache();
|
||||
|
||||
@ -213,6 +216,14 @@ export default class Becca {
|
||||
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 {
|
||||
if (!entityName || !entityId) {
|
||||
return null;
|
||||
|
||||
@ -11,9 +11,10 @@ import BOption from "./entities/boption.js";
|
||||
import BEtapiToken from "./entities/betapi_token.js";
|
||||
import cls from "../services/cls.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 ws from "../services/ws.js";
|
||||
import BTask from "./entities/btask.js";
|
||||
|
||||
const beccaLoaded = new Promise<void>(async (res, rej) => {
|
||||
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`)) {
|
||||
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) {
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
|
||||
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: check against schema.sql which properties really are "optional"
|
||||
|
||||
export interface AttachmentRow {
|
||||
attachmentId?: string;
|
||||
@ -12,6 +13,8 @@ export interface AttachmentRow {
|
||||
dateModified?: string;
|
||||
utcDateModified?: string;
|
||||
utcDateScheduledForErasureSince?: string;
|
||||
isDeleted?: boolean;
|
||||
deleteId?: string;
|
||||
contentLength?: number;
|
||||
content?: Buffer | string;
|
||||
}
|
||||
@ -136,3 +139,13 @@ export interface NoteRow {
|
||||
utcDateModified: string;
|
||||
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 BRecentNote from "./entities/brecent_note.js";
|
||||
import BRevision from "./entities/brevision.js";
|
||||
import BTask from "./entities/btask.js";
|
||||
|
||||
type EntityClass = new (row?: any) => AbstractBeccaEntity<any>;
|
||||
|
||||
@ -21,7 +22,8 @@ const ENTITY_NAME_TO_ENTITY: Record<string, ConstructorData<any> & EntityClass>
|
||||
notes: BNote,
|
||||
options: BOption,
|
||||
recent_notes: BRecentNote,
|
||||
revisions: BRevision
|
||||
revisions: BRevision,
|
||||
tasks: BTask
|
||||
};
|
||||
|
||||
function getEntityFromEntityName(entityName: keyof typeof ENTITY_NAME_TO_ENTITY) {
|
||||
|
||||
@ -18,12 +18,12 @@ import type NoteDetailWidget from "../widgets/note_detail.js";
|
||||
import type { ResolveOptions } from "../widgets/dialogs/delete_notes.js";
|
||||
import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js";
|
||||
import type { ConfirmWithMessageOptions, ConfirmWithTitleOptions } from "../widgets/dialogs/confirm.js";
|
||||
import type { Node } from "../services/tree.js";
|
||||
import type LoadResults from "../services/load_results.js";
|
||||
import type { Attribute } from "../services/attribute_parser.js";
|
||||
import type NoteTreeWidget from "../widgets/note_tree.js";
|
||||
import type { default as NoteContext, GetTextEditorCallback } from "./note_context.js";
|
||||
import type { ContextMenuEvent } from "../menus/context_menu.js";
|
||||
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
|
||||
|
||||
interface Layout {
|
||||
getRootWidget: (appContext: AppContext) => RootWidget;
|
||||
@ -48,21 +48,21 @@ export interface CommandData {
|
||||
* Represents a set of commands that are triggered from the context menu, providing information such as the selected note.
|
||||
*/
|
||||
export interface ContextMenuCommandData extends CommandData {
|
||||
node: Node;
|
||||
notePath: string;
|
||||
node: Fancytree.FancytreeNode;
|
||||
notePath?: string;
|
||||
noteId?: string;
|
||||
selectedOrActiveBranchIds: any; // TODO: Remove any once type is defined
|
||||
selectedOrActiveBranchIds?: any; // TODO: Remove any once type is defined
|
||||
selectedOrActiveNoteIds: any; // TODO: Remove any once type is defined
|
||||
}
|
||||
|
||||
export interface NoteCommandData extends CommandData {
|
||||
notePath: string;
|
||||
notePath?: string;
|
||||
hoistedNoteId?: string;
|
||||
viewScope?: ViewScope;
|
||||
}
|
||||
|
||||
export interface ExecuteCommandData extends CommandData {
|
||||
resolve: unknown;
|
||||
export interface ExecuteCommandData<T> extends CommandData {
|
||||
resolve: (data: T) => void
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,13 +71,17 @@ export interface ExecuteCommandData extends CommandData {
|
||||
export type CommandMappings = {
|
||||
"api-log-messages": CommandData;
|
||||
focusTree: CommandData,
|
||||
focusOnTitle: CommandData;
|
||||
focusOnDetail: CommandData;
|
||||
focusOnSearchDefinition: Required<CommandData>;
|
||||
searchNotes: CommandData & {
|
||||
searchString?: string;
|
||||
ancestorNoteId?: string | null;
|
||||
};
|
||||
closeTocCommand: CommandData;
|
||||
closeHlt: CommandData;
|
||||
showLaunchBarSubtree: CommandData;
|
||||
showRevisions: CommandData;
|
||||
showOptions: CommandData & {
|
||||
section: string;
|
||||
};
|
||||
@ -103,13 +107,20 @@ export type CommandMappings = {
|
||||
showPromptDialog: PromptDialogOptions;
|
||||
showInfoDialog: ConfirmWithMessageOptions;
|
||||
showConfirmDialog: ConfirmWithMessageOptions;
|
||||
showRecentChanges: CommandData & { ancestorNoteId: string };
|
||||
showImportDialog: CommandData & { noteId: string; };
|
||||
openNewNoteSplit: NoteCommandData;
|
||||
openInWindow: NoteCommandData;
|
||||
openNoteInNewTab: CommandData;
|
||||
openNoteInNewSplit: CommandData;
|
||||
openNoteInNewWindow: CommandData;
|
||||
openAboutDialog: CommandData;
|
||||
hideFloatingButtons: {};
|
||||
hideLeftPane: CommandData;
|
||||
showLeftPane: CommandData;
|
||||
hoistNote: CommandData & { noteId: string };
|
||||
leaveProtectedSession: CommandData;
|
||||
enterProtectedSession: CommandData;
|
||||
|
||||
openInTab: ContextMenuCommandData;
|
||||
openNoteInSplit: ContextMenuCommandData;
|
||||
@ -117,9 +128,12 @@ export type CommandMappings = {
|
||||
insertNoteAfter: ContextMenuCommandData;
|
||||
insertChildNote: ContextMenuCommandData;
|
||||
delete: ContextMenuCommandData;
|
||||
editNoteTitle: ContextMenuCommandData;
|
||||
protectSubtree: ContextMenuCommandData;
|
||||
unprotectSubtree: ContextMenuCommandData;
|
||||
openBulkActionsDialog: ContextMenuCommandData;
|
||||
openBulkActionsDialog: ContextMenuCommandData | {
|
||||
selectedOrActiveNoteIds?: string[]
|
||||
};
|
||||
editBranchPrefix: ContextMenuCommandData;
|
||||
convertNoteToAttachment: ContextMenuCommandData;
|
||||
duplicateSubtree: ContextMenuCommandData;
|
||||
@ -138,6 +152,11 @@ export type CommandMappings = {
|
||||
importIntoNote: ContextMenuCommandData;
|
||||
exportNote: ContextMenuCommandData;
|
||||
searchInSubtree: ContextMenuCommandData;
|
||||
moveNoteUp: ContextMenuCommandData;
|
||||
moveNoteDown: ContextMenuCommandData;
|
||||
moveNoteUpInHierarchy: ContextMenuCommandData;
|
||||
moveNoteDownInHierarchy: ContextMenuCommandData;
|
||||
selectAllNotesInParent: ContextMenuCommandData;
|
||||
|
||||
addNoteLauncher: ContextMenuCommandData;
|
||||
addScriptLauncher: ContextMenuCommandData;
|
||||
@ -151,12 +170,16 @@ export type CommandMappings = {
|
||||
callback: (value: NoteDetailWidget | PromiseLike<NoteDetailWidget>) => void;
|
||||
};
|
||||
executeWithTextEditor: CommandData &
|
||||
ExecuteCommandData & {
|
||||
ExecuteCommandData<TextEditor> & {
|
||||
callback?: GetTextEditorCallback;
|
||||
};
|
||||
executeWithCodeEditor: CommandData & ExecuteCommandData;
|
||||
executeWithContentElement: CommandData & ExecuteCommandData;
|
||||
executeWithTypeWidget: CommandData & ExecuteCommandData;
|
||||
executeWithCodeEditor: CommandData & ExecuteCommandData<null>;
|
||||
/**
|
||||
* Called upon when attempting to retrieve the content element of a {@link NoteContext}.
|
||||
* Generally should not be invoked manually, as it is used by {@link NoteContext.getContentElement}.
|
||||
*/
|
||||
executeWithContentElement: CommandData & ExecuteCommandData<JQuery<HTMLElement>>;
|
||||
executeWithTypeWidget: CommandData & ExecuteCommandData<TypeWidget | null>;
|
||||
addTextToActiveEditor: CommandData & {
|
||||
text: string;
|
||||
};
|
||||
@ -166,6 +189,7 @@ export type CommandMappings = {
|
||||
importMarkdownInline: CommandData;
|
||||
showPasswordNotSet: CommandData;
|
||||
showProtectedSessionPasswordDialog: CommandData;
|
||||
showUploadAttachmentsDialog: CommandData & { noteId: string };
|
||||
closeProtectedSessionPasswordDialog: CommandData;
|
||||
copyImageReferenceToClipboard: CommandData;
|
||||
copyImageToClipboard: CommandData;
|
||||
@ -189,6 +213,7 @@ export type CommandMappings = {
|
||||
screen: Screen;
|
||||
};
|
||||
closeTab: CommandData;
|
||||
closeToc: CommandData;
|
||||
closeOtherTabs: CommandData;
|
||||
closeRightTabs: CommandData;
|
||||
closeAllTabs: CommandData;
|
||||
@ -202,9 +227,28 @@ export type CommandMappings = {
|
||||
zoomFactor: string;
|
||||
}
|
||||
|
||||
reEvaluateRightPaneVisibility: CommandData;
|
||||
runActiveNote: CommandData;
|
||||
scrollContainerToCommand: CommandData & {
|
||||
position: number;
|
||||
};
|
||||
scrollToEnd: CommandData;
|
||||
closeThisNoteSplit: CommandData;
|
||||
moveThisNoteSplit: CommandData & { isMovingLeft: boolean; };
|
||||
|
||||
// Geomap
|
||||
deleteFromMap: { noteId: string },
|
||||
openGeoLocation: { noteId: string, event: JQuery.MouseDownEvent }
|
||||
|
||||
toggleZenMode: CommandData;
|
||||
|
||||
updateAttributeList: CommandData & { attributes: Attribute[] };
|
||||
saveAttributes: CommandData;
|
||||
reloadAttributes: CommandData;
|
||||
refreshNoteList: CommandData & { noteId: string; };
|
||||
|
||||
refreshResults: {};
|
||||
refreshSearchDefinition: {};
|
||||
};
|
||||
|
||||
type EventMappings = {
|
||||
@ -247,7 +291,7 @@ type EventMappings = {
|
||||
};
|
||||
noteSwitched: {
|
||||
noteContext: NoteContext;
|
||||
notePath: string | null;
|
||||
notePath?: string | null;
|
||||
};
|
||||
noteSwitchedAndActivatedEvent: {
|
||||
noteContext: NoteContext;
|
||||
@ -262,9 +306,16 @@ type EventMappings = {
|
||||
reEvaluateHighlightsListWidgetVisibility: {
|
||||
noteId: string | undefined;
|
||||
};
|
||||
reEvaluateTocWidgetVisibility: {
|
||||
noteId: string | undefined;
|
||||
};
|
||||
showHighlightsListWidget: {
|
||||
noteId: string;
|
||||
};
|
||||
showSearchError: {
|
||||
error: string;
|
||||
};
|
||||
searchRefreshed: { ntxId?: string | null };
|
||||
hoistedNoteChanged: {
|
||||
noteId: string;
|
||||
ntxId: string | null;
|
||||
@ -279,6 +330,7 @@ type EventMappings = {
|
||||
noteContextReorderEvent: {
|
||||
oldMainNtxId: string;
|
||||
newMainNtxId: string;
|
||||
ntxIdsInOrder: string[];
|
||||
};
|
||||
newNoteContextCreated: {
|
||||
noteContext: NoteContext;
|
||||
@ -287,7 +339,7 @@ type EventMappings = {
|
||||
ntxIds: string[];
|
||||
};
|
||||
exportSvg: {
|
||||
ntxId: string;
|
||||
ntxId: string | null | undefined;
|
||||
};
|
||||
geoMapCreateChildNote: {
|
||||
ntxId: string | null | undefined; // TODO: deduplicate ntxId
|
||||
@ -297,7 +349,12 @@ type EventMappings = {
|
||||
};
|
||||
refreshNoteList: {
|
||||
noteId: string;
|
||||
}
|
||||
};
|
||||
showToc: {
|
||||
noteId: string;
|
||||
};
|
||||
noteTypeMimeChanged: { noteId: string };
|
||||
zenModeChanged: { isEnabled: boolean };
|
||||
};
|
||||
|
||||
export type EventListener<T extends EventNames> = {
|
||||
@ -335,6 +392,8 @@ class AppContext extends Component {
|
||||
layout?: Layout;
|
||||
noteTreeWidget?: NoteTreeWidget;
|
||||
|
||||
lastSearchString?: string;
|
||||
|
||||
constructor(isMainWindow: boolean) {
|
||||
super();
|
||||
|
||||
|
||||
@ -80,8 +80,7 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
|
||||
return promises.length > 0 ? Promise.all(promises) : null;
|
||||
}
|
||||
|
||||
triggerCommand<K extends CommandNames>(name: string, _data?: CommandMappings[K]): Promise<unknown> | undefined | null {
|
||||
const data = _data || {};
|
||||
triggerCommand<K extends CommandNames>(name: K, data?: CommandMappings[K]): Promise<unknown> | undefined | null {
|
||||
const fun = (this as any)[`${name}Command`];
|
||||
|
||||
if (fun) {
|
||||
|
||||
@ -9,8 +9,9 @@ import hoistedNoteService from "../services/hoisted_note.js";
|
||||
import options from "../services/options.js";
|
||||
import type { ViewScope } from "../services/link.js";
|
||||
import type FNote from "../entities/fnote.js";
|
||||
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
|
||||
|
||||
interface SetNoteOpts {
|
||||
export interface SetNoteOpts {
|
||||
triggerSwitchEvent?: unknown;
|
||||
viewScope?: ViewScope;
|
||||
}
|
||||
@ -288,8 +289,8 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
||||
hasNoteList() {
|
||||
return (
|
||||
this.note &&
|
||||
this.viewScope?.viewMode === "default" &&
|
||||
this.note.hasChildren() &&
|
||||
["default", "contextual-help"].includes(this.viewScope?.viewMode ?? "") &&
|
||||
(this.note.hasChildren() || this.note.getLabelValue("viewType") === "calendar") &&
|
||||
["book", "text", "code"].includes(this.note.type) &&
|
||||
this.note.mime !== "text/x-sqlite;schema=trilium" &&
|
||||
!this.note.isLabelTruthy("hideChildrenOverview")
|
||||
@ -319,6 +320,15 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise which will retrieve the JQuery element of the content of this note context.
|
||||
*
|
||||
* Do note that retrieving the content element needs to be handled by the type widget, which is the one which
|
||||
* provides the content element by listening to the `executeWithContentElement` event. Not all note types support
|
||||
* this.
|
||||
*
|
||||
* If no content could be determined `null` is returned instead.
|
||||
*/
|
||||
async getContentElement() {
|
||||
return this.timeout<JQuery<HTMLElement>>(
|
||||
new Promise((resolve) =>
|
||||
@ -332,7 +342,7 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
||||
|
||||
async getTypeWidget() {
|
||||
return this.timeout(
|
||||
new Promise((resolve) =>
|
||||
new Promise<TypeWidget | null>((resolve) =>
|
||||
appContext.triggerCommand("executeWithTypeWidget", {
|
||||
resolve,
|
||||
ntxId: this.ntxId
|
||||
|
||||
@ -90,6 +90,10 @@ export default class RootCommandExecutor extends Component {
|
||||
await appContext.tabManager.openTabWithNoteWithHoisting("_backendLog", { activate: true });
|
||||
}
|
||||
|
||||
async showHelpCommand() {
|
||||
await this.showAndHoistSubtree("_help");
|
||||
}
|
||||
|
||||
async showLaunchBarSubtreeCommand() {
|
||||
const rootNote = utils.isMobile() ? "_lbMobileRoot" : "_lbRoot";
|
||||
await this.showAndHoistSubtree(rootNote);
|
||||
@ -174,6 +178,13 @@ export default class RootCommandExecutor extends Component {
|
||||
for (const window of windows) window[action]();
|
||||
}
|
||||
|
||||
toggleZenModeCommand() {
|
||||
const $body = $("body");
|
||||
$body.toggleClass("zen");
|
||||
const isEnabled = $body.hasClass("zen");
|
||||
appContext.triggerEvent("zenModeChanged", { isEnabled });
|
||||
}
|
||||
|
||||
firstTabCommand() {
|
||||
this.#goToTab(1);
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import { t } from "./services/i18n.js";
|
||||
import options from "./services/options.js";
|
||||
import type ElectronRemote from "@electron/remote";
|
||||
import type Electron from "electron";
|
||||
import "../stylesheets/bootstrap.scss";
|
||||
|
||||
await appContext.earlyInit();
|
||||
|
||||
@ -50,6 +51,7 @@ function initOnElectron() {
|
||||
const currentWindow = electronRemote.getCurrentWindow();
|
||||
const style = window.getComputedStyle(document.body);
|
||||
|
||||
initDarkOrLightMode(style);
|
||||
initTransparencyEffects(style, currentWindow);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
1393
src/public/app/doc_notes/en/User Guide/!!!meta.json
Normal 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 & 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>
|
||||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
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 |
@ -0,0 +1,55 @@
|
||||
<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>Export as PDF</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1 data-trilium-h1>Export as PDF</h1>
|
||||
|
||||
<div class="ck-content">
|
||||
<figure class="image image-style-align-right image_resized" style="width:50.63%;">
|
||||
<img style="aspect-ratio:951/432;" src="Export as PDF_image.png" width="951"
|
||||
height="432">
|
||||
<figcaption>Screenshot of the note contextual menu indicating the “Export as PDF”
|
||||
option.</figcaption>
|
||||
</figure>
|
||||
<p>On the desktop application of Trilium it is possible to export a note
|
||||
as PDF. On the server or PWA (mobile), the option is not available due
|
||||
to technical constraints and it will be hidden.</p>
|
||||
<p>To print a note, select the
|
||||
<img src="2_Export as PDF_image.png" width="29"
|
||||
height="31">button to the right of the note and select <i>Export as PDF</i>.</p>
|
||||
<p>Afterwards you will be prompted to select where to save the PDF file.
|
||||
Upon confirmation, the resulting PDF will be opened automatically using
|
||||
the default/system application configured for PDFs.</p>
|
||||
<p>Should you encounter any visual issues in the resulting PDF file (e.g.
|
||||
a table does not fit properly, there is cut off text, etc.) feel free to
|
||||
<a
|
||||
href="#root/OeKBfN6JbMIq/jRV1MPt4mNSP/hrC6xn7hnDq5">report the issue</a>. In this case, it's best to offer a sample note (click
|
||||
on the
|
||||
<img src="2_Export as PDF_image.png" width="29" height="31">button, select Export note → This note and all of its descendants → HTML
|
||||
in ZIP archive). Make sure not to accidentally leak any personal information.</p>
|
||||
<h2>Landscape mode</h2>
|
||||
<p>When exporting to PDF, there are no customizable settings such as page
|
||||
orientation, size, etc. However, it is possible to specify a given note
|
||||
to be printed as a PDF in landscape mode by adding the <code>#printLandscape</code> attribute
|
||||
to it (see <a class="reference-link" href="#root/9QRytp0ZYFIf/PnO38wN0ffOA">Adding an attribute to a note</a>).</p>
|
||||
<h2>Page size</h2>
|
||||
<p>By default, the resulting PDF will be in Letter format. It is possible
|
||||
to adjust it to another page size via the <code>#printPageSize</code> attribute,
|
||||
with one of the following values: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.</p>
|
||||
<h2>Keyboard shortcut</h2>
|
||||
<p>It's possible to trigger the export to PDF from the keyboard by going
|
||||
to <i>Keyboard shortcuts</i> and assigning a key combination
|
||||
for the <code>exportAsPdf</code> action.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
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 |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 323 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 191 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 515 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 397 KiB |
|
After Width: | Height: | Size: 5.2 KiB |