mirror of
https://github.com/zadam/trilium.git
synced 2025-11-11 15:55:52 +01:00
Compare commits
1 Commits
v0.99.4
...
algolia_v1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
baed93e749 |
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.git
|
||||||
|
.idea
|
||||||
|
/bin
|
||||||
|
/dist
|
||||||
|
/docs
|
||||||
|
/npm-debug.log
|
||||||
|
node_modules
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
root = true
|
|
||||||
|
|
||||||
[*.{js,ts,tsx}]
|
|
||||||
charset = utf-8
|
|
||||||
end_of_line = lf
|
|
||||||
indent_size = 4
|
|
||||||
indent_style = space
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.sh]
|
|
||||||
end_of_line = lf
|
|
||||||
|
|
||||||
[{server,translation}.json]
|
|
||||||
charset = utf-8
|
|
||||||
end_of_line = lf
|
|
||||||
indent_size = 2
|
|
||||||
indent_style = space
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.yml]
|
|
||||||
indent_size = 2
|
|
||||||
indent_style = space
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
21
.gitattributes
vendored
21
.gitattributes
vendored
@@ -1,21 +0,0 @@
|
|||||||
# Mark files as auto-generated to simplify reviews.
|
|
||||||
package-lock.json linguist-generated=true
|
|
||||||
**/package-lock.json linguist-generated=true
|
|
||||||
apps/server/src/assets/doc_notes/en/User[[:space:]]Guide/** linguist-generated
|
|
||||||
|
|
||||||
# Ignore from GitHub language stats.
|
|
||||||
apps/server/src/assets/doc_notes/en/User[[:space:]]Guide/**/*.html eol=lf
|
|
||||||
apps/server/src/assets/doc_notes/** linguist-vendored=true
|
|
||||||
apps/edit-docs/demo/** linguist-vendored=true
|
|
||||||
docs/** linguist-vendored=true
|
|
||||||
|
|
||||||
# Normalize line endings.
|
|
||||||
docs/**/*.md eol=lf
|
|
||||||
docs/**/*.json eol=lf
|
|
||||||
demo/**/*.html eol=lf
|
|
||||||
demo/**/*.json eol=lf
|
|
||||||
demo/**/*.svg eol=lf
|
|
||||||
demo/**/*.txt eol=lf
|
|
||||||
demo/**/*.js eol=lf
|
|
||||||
demo/**/*.css eol=lf
|
|
||||||
*.sh eol=lf
|
|
||||||
6
.github/FUNDING.yml
vendored
6
.github/FUNDING.yml
vendored
@@ -1,6 +1,4 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: [eliandoran]
|
github: [zadam]
|
||||||
custom: ["https://paypal.me/eliandoran"]
|
custom: ["https://paypal.me/za4am"]
|
||||||
liberapay: ElianDoran
|
|
||||||
buy_me_a_coffee: eliandoran
|
|
||||||
|
|||||||
38
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
38
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,18 +1,20 @@
|
|||||||
name: Bug Report
|
name: Bug Report
|
||||||
description: Report a bug
|
description: Report a bug
|
||||||
type: "Bug"
|
title: "(Bug report) "
|
||||||
|
labels: "Type: Bug"
|
||||||
body:
|
body:
|
||||||
- type: textarea
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
label: Description
|
label: Preflight Checklist
|
||||||
description: A clear and concise description of the bug and any additional information.
|
description: Please ensure you've completed all of the following.
|
||||||
validations:
|
options:
|
||||||
required: true
|
- label: I have searched the [issue tracker](https://www.github.com/zadam/trilium/issues) for a bug report that matches the one I want to file, without success.
|
||||||
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: TriliumNext Version
|
label: Trilium Version
|
||||||
description: What version of TriliumNext are you using?
|
description: What version of Trilium are you using?
|
||||||
placeholder: 0.90.0-beta
|
placeholder: 0.48.0-beta
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
@@ -29,7 +31,7 @@ body:
|
|||||||
- type: dropdown
|
- type: dropdown
|
||||||
attributes:
|
attributes:
|
||||||
label: What is your setup?
|
label: What is your setup?
|
||||||
description: https://triliumnext.github.io/Docs/Wiki/quick-start.html
|
description: https://github.com/zadam/trilium/wiki#choose-the-setup
|
||||||
options:
|
options:
|
||||||
- Local (no sync)
|
- Local (no sync)
|
||||||
- Local + server sync
|
- Local + server sync
|
||||||
@@ -45,7 +47,17 @@ body:
|
|||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Error logs
|
label: Expected Behavior
|
||||||
description: Please provide error logs, see [wiki page](https://triliumnext.github.io/Docs/Wiki/error-logs.html) for instructions on how to submit them.
|
description: A clear and concise description of what you expected to happen.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Actual Behavior
|
||||||
|
description: A clear description of what actually happens.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional Information
|
||||||
|
description: If your problem needs further explanation, or if the issue you're seeing cannot be reproduced in a gist, please add more information here.
|
||||||
|
|||||||
14
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
14
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,11 +1,19 @@
|
|||||||
name: Feature Request
|
name: Feature Request
|
||||||
description: Ask for a new feature to be added
|
description: Report a bug
|
||||||
type: "Feature"
|
title: "(Feature request) "
|
||||||
|
labels: "Type: Enhancement"
|
||||||
body:
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Preflight Checklist
|
||||||
|
description: Please ensure you've completed all of the following.
|
||||||
|
options:
|
||||||
|
- label: I have searched the [issue tracker](https://www.github.com/zadam/trilium/issues) for a feature request that matches the one I want to file, without success.
|
||||||
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe feature
|
label: Describe feature
|
||||||
description: A clear and concise description of what you want to be added.
|
description: A clear and concise description of what you want to be added..
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
10
.github/ISSUE_TEMPLATE/task.yml
vendored
10
.github/ISSUE_TEMPLATE/task.yml
vendored
@@ -1,10 +0,0 @@
|
|||||||
name: Task
|
|
||||||
description: Create a new Task
|
|
||||||
type: "Task"
|
|
||||||
body:
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Describe Task
|
|
||||||
description: A clear and concise description of what the task is about.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
187
.github/actions/build-electron/action.yml
vendored
187
.github/actions/build-electron/action.yml
vendored
@@ -1,187 +0,0 @@
|
|||||||
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"
|
|
||||||
required: true
|
|
||||||
arch:
|
|
||||||
description: "The architecture to build for: x64, arm64"
|
|
||||||
required: true
|
|
||||||
shell:
|
|
||||||
description: "Which shell to use"
|
|
||||||
required: true
|
|
||||||
forge_platform:
|
|
||||||
description: "The --platform to pass to Electron Forge"
|
|
||||||
required: true
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
# Certificate setup
|
|
||||||
- name: Import Apple certificates
|
|
||||||
if: inputs.os == 'macos'
|
|
||||||
uses: apple-actions/import-codesign-certs@v5
|
|
||||||
with:
|
|
||||||
p12-file-base64: ${{ env.APPLE_APP_CERTIFICATE_BASE64 }}
|
|
||||||
p12-password: ${{ env.APPLE_APP_CERTIFICATE_PASSWORD }}
|
|
||||||
keychain: build-app-${{ github.run_id }}
|
|
||||||
keychain-password: ${{ github.run_id }}
|
|
||||||
|
|
||||||
- name: Install Installer certificate
|
|
||||||
if: inputs.os == 'macos'
|
|
||||||
uses: apple-actions/import-codesign-certs@v5
|
|
||||||
with:
|
|
||||||
p12-file-base64: ${{ env.APPLE_INSTALLER_CERTIFICATE_BASE64 }}
|
|
||||||
p12-password: ${{ env.APPLE_INSTALLER_CERTIFICATE_PASSWORD }}
|
|
||||||
keychain: build-installer-${{ github.run_id }}
|
|
||||||
keychain-password: ${{ github.run_id }}
|
|
||||||
|
|
||||||
- name: Verify certificates
|
|
||||||
if: inputs.os == 'macos'
|
|
||||||
shell: ${{ inputs.shell }}
|
|
||||||
run: |
|
|
||||||
echo "Available signing identities in app keychain:"
|
|
||||||
security find-identity -v -p codesigning build-app-${{ github.run_id }}.keychain
|
|
||||||
|
|
||||||
echo "Available signing identities in installer keychain:"
|
|
||||||
security find-identity -v -p codesigning build-installer-${{ github.run_id }}.keychain
|
|
||||||
|
|
||||||
# Make the keychains searchable
|
|
||||||
security list-keychains -d user -s build-app-${{ github.run_id }}.keychain build-installer-${{ github.run_id }}.keychain $(security list-keychains -d user | tr -d '"')
|
|
||||||
security default-keychain -s build-app-${{ github.run_id }}.keychain
|
|
||||||
security unlock-keychain -p ${{ github.run_id }} build-app-${{ github.run_id }}.keychain
|
|
||||||
security unlock-keychain -p ${{ github.run_id }} build-installer-${{ github.run_id }}.keychain
|
|
||||||
security set-keychain-settings -t 3600 -l build-app-${{ github.run_id }}.keychain
|
|
||||||
security set-keychain-settings -t 3600 -l build-installer-${{ github.run_id }}.keychain
|
|
||||||
|
|
||||||
- name: Set up Python and other macOS dependencies
|
|
||||||
if: ${{ inputs.os == 'macos' }}
|
|
||||||
shell: ${{ inputs.shell }}
|
|
||||||
run: |
|
|
||||||
brew install python-setuptools
|
|
||||||
brew install create-dmg
|
|
||||||
|
|
||||||
- name: Install dependencies for RPM and Flatpak package building
|
|
||||||
if: ${{ inputs.os == 'linux' }}
|
|
||||||
shell: ${{ inputs.shell }}
|
|
||||||
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
|
|
||||||
|
|
||||||
- name: Update build info
|
|
||||||
shell: ${{ inputs.shell }}
|
|
||||||
run: pnpm run chore:update-build-info
|
|
||||||
|
|
||||||
# Critical debugging configuration
|
|
||||||
- name: Run electron-forge build with enhanced logging
|
|
||||||
shell: ${{ inputs.shell }}
|
|
||||||
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 }}
|
|
||||||
WINDOWS_SIGN_EXECUTABLE: ${{ env.WINDOWS_SIGN_EXECUTABLE }}
|
|
||||||
TRILIUM_ARTIFACT_NAME_HINT: TriliumNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}
|
|
||||||
TARGET_ARCH: ${{ inputs.arch }}
|
|
||||||
run: pnpm run --filter desktop electron-forge:make --arch=${{ inputs.arch }} --platform=${{ inputs.forge_platform }}
|
|
||||||
|
|
||||||
# Add DMG signing step
|
|
||||||
- name: Sign DMG
|
|
||||||
if: inputs.os == 'macos'
|
|
||||||
shell: ${{ inputs.shell }}
|
|
||||||
run: |
|
|
||||||
echo "Signing DMG file..."
|
|
||||||
dmg_file=$(find ./apps/desktop/dist -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-app-${{ github.run_id }}.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: ${{ inputs.shell }}
|
|
||||||
run: |
|
|
||||||
echo "Verifying code signing for all artifacts..."
|
|
||||||
|
|
||||||
# First check the .app bundle
|
|
||||||
echo "Looking for .app bundle..."
|
|
||||||
app_bundle=$(find ./apps/desktop/dist -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 ./apps/desktop/dist -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 ./apps/desktop/dist -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: Sign the RPM
|
|
||||||
if: inputs.os == 'linux'
|
|
||||||
shell: ${{ inputs.shell }}
|
|
||||||
run: |
|
|
||||||
echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import
|
|
||||||
|
|
||||||
# Import the key into RPM for verification
|
|
||||||
gpg --export -a > pubkey
|
|
||||||
rpm --import pubkey
|
|
||||||
rm pubkey
|
|
||||||
|
|
||||||
# Sign the RPM
|
|
||||||
rpm_file=$(find ./apps/desktop/upload -name "*.rpm" -print -quit)
|
|
||||||
rpmsign --define "_gpg_name Trilium Notes Signing Key <triliumnotes@outlook.com>" --addsign "$rpm_file"
|
|
||||||
rpm -Kv "$rpm_file"
|
|
||||||
|
|
||||||
# Validate code signing
|
|
||||||
if ! rpm -K "$rpm_file" | grep -q "digests signatures OK"; then
|
|
||||||
echo .rpm file not signed
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
33
.github/actions/build-server/action.yml
vendored
33
.github/actions/build-server/action.yml
vendored
@@ -1,33 +0,0 @@
|
|||||||
inputs:
|
|
||||||
os:
|
|
||||||
description: "One of the supported platforms: windows"
|
|
||||||
required: true
|
|
||||||
arch:
|
|
||||||
description: "The architecture to build for: x64, arm64"
|
|
||||||
required: true
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- name: Set up node & dependencies
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: "pnpm"
|
|
||||||
- name: Install dependencies
|
|
||||||
shell: bash
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
- name: Run Linux server build
|
|
||||||
env:
|
|
||||||
MATRIX_ARCH: ${{ inputs.arch }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
pnpm run chore:update-build-info
|
|
||||||
pnpm run --filter server package
|
|
||||||
- name: Prepare artifacts
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
mkdir -p upload
|
|
||||||
file=$(find ./apps/server/out -name '*.tar.xz' -print -quit)
|
|
||||||
name=${{ github.ref_name }}
|
|
||||||
cp "$file" "upload/TriliumNotes-Server-${name//\//-}-${{ inputs.os }}-${{ inputs.arch }}.tar.xz"
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
name: "Deploy to Cloudflare Pages"
|
|
||||||
description: "Deploys to Cloudflare Pages on either a temporary branch with preview comment, or on the production version if on the main branch."
|
|
||||||
inputs:
|
|
||||||
project_name:
|
|
||||||
description: "CloudFlare Pages project name"
|
|
||||||
comment_body:
|
|
||||||
description: "The message to display when deployment is ready"
|
|
||||||
default: "Deployment is ready."
|
|
||||||
required: false
|
|
||||||
production_url:
|
|
||||||
description: "The URL to mention as the production URL."
|
|
||||||
required: true
|
|
||||||
deploy_dir:
|
|
||||||
description: "The directory from which to deploy."
|
|
||||||
required: true
|
|
||||||
cloudflare_api_token:
|
|
||||||
description: "The Cloudflare API token to use for deployment."
|
|
||||||
required: true
|
|
||||||
cloudflare_account_id:
|
|
||||||
description: "The Cloudflare account ID to use for deployment."
|
|
||||||
required: true
|
|
||||||
github_token:
|
|
||||||
description: "The GitHub token to use for posting PR comments."
|
|
||||||
required: true
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
# Install wrangler globally to avoid workspace issues
|
|
||||||
- name: Install Wrangler
|
|
||||||
shell: bash
|
|
||||||
run: npm install -g wrangler
|
|
||||||
|
|
||||||
# Deploy using Wrangler (use pre-installed wrangler)
|
|
||||||
- name: Deploy to Cloudflare Pages
|
|
||||||
id: deploy
|
|
||||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
|
||||||
uses: cloudflare/wrangler-action@v3
|
|
||||||
with:
|
|
||||||
apiToken: ${{ inputs.cloudflare_api_token }}
|
|
||||||
accountId: ${{ inputs.cloudflare_account_id }}
|
|
||||||
command: pages deploy ${{ inputs.deploy_dir }} --project-name=${{ inputs.project_name}} --branch=${{ github.ref_name }}
|
|
||||||
wranglerVersion: '' # Use pre-installed version
|
|
||||||
|
|
||||||
# Deploy preview for PRs
|
|
||||||
- name: Deploy Preview to Cloudflare Pages
|
|
||||||
id: preview-deployment
|
|
||||||
if: github.event_name == 'pull_request'
|
|
||||||
uses: cloudflare/wrangler-action@v3
|
|
||||||
with:
|
|
||||||
apiToken: ${{ inputs.cloudflare_api_token }}
|
|
||||||
accountId: ${{ inputs.cloudflare_account_id }}
|
|
||||||
command: pages deploy ${{ inputs.deploy_dir }} --project-name=${{ inputs.project_name}} --branch=pr-${{ github.event.pull_request.number }}
|
|
||||||
wranglerVersion: '' # Use pre-installed version
|
|
||||||
|
|
||||||
# Post deployment URL as PR comment
|
|
||||||
- name: Comment PR with Preview URL
|
|
||||||
if: github.event_name == 'pull_request'
|
|
||||||
uses: actions/github-script@v8
|
|
||||||
env:
|
|
||||||
COMMENT_BODY: ${{ inputs.comment_body }}
|
|
||||||
PRODUCTION_URL: ${{ inputs.production_url }}
|
|
||||||
PROJECT_NAME: ${{ inputs.project_name }}
|
|
||||||
with:
|
|
||||||
github-token: ${{ inputs.github_token }}
|
|
||||||
script: |
|
|
||||||
const prNumber = context.issue.number;
|
|
||||||
// Construct preview URL based on Cloudflare Pages pattern
|
|
||||||
const projectName = process.env.PROJECT_NAME;
|
|
||||||
const previewUrl = `https://pr-${prNumber}.${projectName}.pages.dev`;
|
|
||||||
|
|
||||||
// Check if we already commented
|
|
||||||
const comments = await github.rest.issues.listComments({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
issue_number: prNumber
|
|
||||||
});
|
|
||||||
|
|
||||||
const customMessage = process.env.COMMENT_BODY;
|
|
||||||
const botComment = comments.data.find(comment =>
|
|
||||||
comment.user.type === 'Bot' &&
|
|
||||||
comment.body.includes(customMessage)
|
|
||||||
);
|
|
||||||
|
|
||||||
const mainUrl = process.env.PRODUCTION_URL;
|
|
||||||
const commentBody = `${customMessage}!\n\n🔗 Preview URL: ${previewUrl}\n📖 Production URL: ${mainUrl}\n\n✅ All checks passed\n\n_This preview will be updated automatically with new commits._`;
|
|
||||||
|
|
||||||
if (botComment) {
|
|
||||||
// Update existing comment
|
|
||||||
await github.rest.issues.updateComment({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
comment_id: botComment.id,
|
|
||||||
body: commentBody
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Create new comment
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
issue_number: prNumber,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
body: commentBody
|
|
||||||
});
|
|
||||||
}
|
|
||||||
79
.github/actions/report-size/action.yml
vendored
79
.github/actions/report-size/action.yml
vendored
@@ -1,79 +0,0 @@
|
|||||||
name: 'Bundle size reporter'
|
|
||||||
description: 'Post bundle size difference compared to another branch'
|
|
||||||
inputs:
|
|
||||||
branch:
|
|
||||||
description: 'Branch to compare to'
|
|
||||||
required: true
|
|
||||||
default: 'main'
|
|
||||||
paths:
|
|
||||||
description:
|
|
||||||
'Paths to json file bundle size report or folder containing bundles'
|
|
||||||
required: true
|
|
||||||
default: '/'
|
|
||||||
onlyDiff:
|
|
||||||
description: 'Report only different sizes'
|
|
||||||
required: false
|
|
||||||
default: 'false'
|
|
||||||
filter:
|
|
||||||
description: 'Regex filter based on file path'
|
|
||||||
required: false
|
|
||||||
unit:
|
|
||||||
description: 'Size unit'
|
|
||||||
required: false
|
|
||||||
default: 'KB'
|
|
||||||
|
|
||||||
# Comment inputs
|
|
||||||
comment:
|
|
||||||
description: 'Post comment'
|
|
||||||
required: false
|
|
||||||
default: 'true'
|
|
||||||
header:
|
|
||||||
description: 'Comment header'
|
|
||||||
required: false
|
|
||||||
default: 'Bundle size report'
|
|
||||||
append:
|
|
||||||
description: 'Append comment'
|
|
||||||
required: false
|
|
||||||
default: 'false'
|
|
||||||
ghToken:
|
|
||||||
description: 'Github token'
|
|
||||||
required: false
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: 'composite'
|
|
||||||
steps:
|
|
||||||
# Checkout branch to compare to [required]
|
|
||||||
- name: Checkout base branch
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
ref: ${{ inputs.branch }}
|
|
||||||
path: br-base
|
|
||||||
token: ${{ inputs.ghToken }}
|
|
||||||
|
|
||||||
# Generate the bundle size difference report [required]
|
|
||||||
- name: Generate report
|
|
||||||
id: bundleSize
|
|
||||||
uses: nejcm/bundle-size-reporter-action@v1.4.1
|
|
||||||
with:
|
|
||||||
paths: ${{ inputs.paths }}
|
|
||||||
onlyDiff: ${{ inputs.onlyDiff }}
|
|
||||||
filter: ${{ inputs.filter }}
|
|
||||||
unit: ${{ inputs.unit }}
|
|
||||||
|
|
||||||
# Post github action summary
|
|
||||||
- name: Post summary
|
|
||||||
if: ${{ steps.bundleSize.outputs.hasDifferences == 'true' }} # post only in case of changes
|
|
||||||
run: |
|
|
||||||
echo '${{ steps.bundleSize.outputs.summary }}' >> $GITHUB_STEP_SUMMARY
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
# Post github action comment
|
|
||||||
- name: Post comment
|
|
||||||
uses: marocchino/sticky-pull-request-comment@v2
|
|
||||||
if: ${{ steps.bundleSize.outputs.hasDifferences == 'true' }} # post only in case of changes
|
|
||||||
with:
|
|
||||||
number: ${{ github.event.pull_request.number }}
|
|
||||||
header: ${{ inputs.header }}
|
|
||||||
append: ${{ inputs.append }}
|
|
||||||
message: '${{ steps.bundleSize.outputs.summary }}'
|
|
||||||
GITHUB_TOKEN: ${{ inputs.ghToken }}
|
|
||||||
18
.github/workflows/checks.yml
vendored
18
.github/workflows/checks.yml
vendored
@@ -1,18 +0,0 @@
|
|||||||
name: Checks
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request_target:
|
|
||||||
types: [synchronize]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
main:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
steps:
|
|
||||||
- name: Check if PRs have conflicts
|
|
||||||
uses: eps1lon/actions-label-merge-conflict@v3
|
|
||||||
if: github.repository == ${{ vars.REPO_MAIN }}
|
|
||||||
with:
|
|
||||||
dirtyLabel: "merge-conflicts"
|
|
||||||
repoToken: "${{ secrets.MERGE_CONFLICT_LABEL_PAT }}"
|
|
||||||
71
.github/workflows/codeql-analysis.yml
vendored
Normal file
71
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: '37 4 * * 1'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'javascript' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||||
|
# Learn more:
|
||||||
|
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
||||||
100
.github/workflows/codeql.yml
vendored
100
.github/workflows/codeql.yml
vendored
@@ -1,100 +0,0 @@
|
|||||||
# For most projects, this workflow file will not need changing; you simply need
|
|
||||||
# to commit it to your repository.
|
|
||||||
#
|
|
||||||
# You may wish to alter this file to override the set of languages analyzed,
|
|
||||||
# or to provide custom queries or build logic.
|
|
||||||
#
|
|
||||||
# ******** NOTE ********
|
|
||||||
# We have attempted to detect the languages in your repository. Please check
|
|
||||||
# the `language` matrix defined below to confirm you have the correct set of
|
|
||||||
# supported CodeQL languages.
|
|
||||||
#
|
|
||||||
name: "CodeQL Advanced"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "main" ]
|
|
||||||
schedule:
|
|
||||||
- cron: '20 7 * * 0'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze (${{ matrix.language }})
|
|
||||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
|
||||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
|
||||||
# - https://gh.io/supported-runners-and-hardware-resources
|
|
||||||
# - https://gh.io/using-larger-runners (GitHub.com only)
|
|
||||||
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
|
|
||||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
|
||||||
permissions:
|
|
||||||
# required for all workflows
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
# required to fetch internal or private CodeQL packs
|
|
||||||
packages: read
|
|
||||||
|
|
||||||
# only required for workflows in private repositories
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- language: actions
|
|
||||||
build-mode: none
|
|
||||||
- language: javascript-typescript
|
|
||||||
build-mode: none
|
|
||||||
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
|
|
||||||
# Use `c-cpp` to analyze code written in C, C++ or both
|
|
||||||
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
|
|
||||||
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
|
||||||
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
|
|
||||||
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
|
|
||||||
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
|
|
||||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
# Add any setup steps before running the `github/codeql-action/init` action.
|
|
||||||
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
|
||||||
# or others). This is typically only required for manual builds.
|
|
||||||
# - name: Setup runtime (example)
|
|
||||||
# uses: actions/setup-example@v1
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v4
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
build-mode: ${{ matrix.build-mode }}
|
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
||||||
# By default, queries listed here will override any specified in a config file.
|
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
||||||
|
|
||||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
|
||||||
# queries: security-extended,security-and-quality
|
|
||||||
|
|
||||||
# If the analyze step fails for one of the languages you are analyzing with
|
|
||||||
# "We were unable to automatically build your code", modify the matrix above
|
|
||||||
# to set the build mode to "manual" for that language. Then modify this step
|
|
||||||
# to build your code.
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
|
||||||
- if: matrix.build-mode == 'manual'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo 'If you are using a "manual" build mode for one or more of the' \
|
|
||||||
'languages you are analyzing, replace this with the commands to build' \
|
|
||||||
'your code, for example:'
|
|
||||||
echo ' make bootstrap'
|
|
||||||
echo ' make release'
|
|
||||||
exit 1
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v4
|
|
||||||
with:
|
|
||||||
category: "/language:${{matrix.language}}"
|
|
||||||
78
.github/workflows/deploy-docs.yml
vendored
78
.github/workflows/deploy-docs.yml
vendored
@@ -1,78 +0,0 @@
|
|||||||
name: Deploy Documentation
|
|
||||||
|
|
||||||
on:
|
|
||||||
# Trigger on push to main branch
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- master # Also support master branch
|
|
||||||
# Only run when docs files change
|
|
||||||
paths:
|
|
||||||
- 'docs/**'
|
|
||||||
- 'apps/edit-docs/**'
|
|
||||||
- 'apps/build-docs/**'
|
|
||||||
- 'packages/share-theme/**'
|
|
||||||
|
|
||||||
# Allow manual triggering from Actions tab
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
# Run on pull requests for preview deployments
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- master
|
|
||||||
paths:
|
|
||||||
- 'docs/**'
|
|
||||||
- 'apps/edit-docs/**'
|
|
||||||
- 'apps/build-docs/**'
|
|
||||||
- 'packages/share-theme/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-deploy:
|
|
||||||
name: Build and Deploy Documentation
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 10
|
|
||||||
|
|
||||||
# Required permissions for deployment
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
deployments: write
|
|
||||||
pull-requests: write # For PR preview comments
|
|
||||||
id-token: write # For OIDC authentication (if needed)
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Setup pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: '24'
|
|
||||||
cache: 'pnpm'
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Trigger build of documentation
|
|
||||||
run: pnpm docs:build
|
|
||||||
|
|
||||||
- name: Validate Built Site
|
|
||||||
run: |
|
|
||||||
test -f site/index.html || (echo "ERROR: site/index.html not found" && exit 1)
|
|
||||||
test -f site/developer-guide/index.html || (echo "ERROR: site/developer-guide/index.html not found" && exit 1)
|
|
||||||
echo "✓ User Guide and Developer Guide built successfully"
|
|
||||||
|
|
||||||
- name: Deploy
|
|
||||||
uses: ./.github/actions/deploy-to-cloudflare-pages
|
|
||||||
if: github.repository == ${{ vars.REPO_MAIN }}
|
|
||||||
with:
|
|
||||||
project_name: "trilium-docs"
|
|
||||||
comment_body: "📚 Documentation preview is ready"
|
|
||||||
production_url: "https://docs.triliumnotes.org"
|
|
||||||
deploy_dir: "site"
|
|
||||||
cloudflare_api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
||||||
cloudflare_account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
128
.github/workflows/dev.yml
vendored
128
.github/workflows/dev.yml
vendored
@@ -1,128 +0,0 @@
|
|||||||
name: Dev
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ main ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ main ]
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
GHCR_REGISTRY: ghcr.io
|
|
||||||
DOCKERHUB_REGISTRY: docker.io
|
|
||||||
IMAGE_NAME: ${{ github.repository}}
|
|
||||||
TEST_TAG: ${{ github.repository}}:test
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write # for PR comments
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test_dev:
|
|
||||||
name: Test development
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout the repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- name: Set up node & dependencies
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: "pnpm"
|
|
||||||
- run: pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Typecheck
|
|
||||||
run: pnpm typecheck
|
|
||||||
|
|
||||||
- name: Run the unit tests
|
|
||||||
run: pnpm run test:all
|
|
||||||
|
|
||||||
build_docker:
|
|
||||||
name: Build Docker image
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- test_dev
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
- name: Update build info
|
|
||||||
run: pnpm run chore:update-build-info
|
|
||||||
- name: Trigger client build
|
|
||||||
run: pnpm client:build
|
|
||||||
- name: Send client bundle stats to RelativeCI
|
|
||||||
if: false
|
|
||||||
uses: relative-ci/agent-action@v3
|
|
||||||
with:
|
|
||||||
webpackStatsFile: ./apps/client/dist/webpack-stats.json
|
|
||||||
key: ${{ secrets.RELATIVE_CI_CLIENT_KEY }}
|
|
||||||
- name: Trigger server build
|
|
||||||
run: pnpm run server:build
|
|
||||||
- uses: docker/setup-buildx-action@v3
|
|
||||||
- uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: apps/server
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
test_docker:
|
|
||||||
name: Check Docker build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- build_docker
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- dockerfile: Dockerfile.alpine
|
|
||||||
- dockerfile: Dockerfile
|
|
||||||
steps:
|
|
||||||
- name: Checkout the repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Update build info
|
|
||||||
run: pnpm run chore:update-build-info
|
|
||||||
- name: Trigger build
|
|
||||||
run: pnpm server:build
|
|
||||||
|
|
||||||
- name: Set IMAGE_NAME to lowercase
|
|
||||||
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
|
|
||||||
- name: Set TEST_TAG to lowercase
|
|
||||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Build and export to Docker
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: apps/server
|
|
||||||
file: apps/server/${{ matrix.dockerfile }}
|
|
||||||
load: true
|
|
||||||
tags: ${{ env.TEST_TAG }}
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
|
|
||||||
- name: Validate container run output
|
|
||||||
run: |
|
|
||||||
CONTAINER_ID=$(docker run -d --log-driver=journald --rm --name trilium_local ${{ env.TEST_TAG }})
|
|
||||||
echo "Container ID: $CONTAINER_ID"
|
|
||||||
|
|
||||||
- name: Wait for the healthchecks to pass
|
|
||||||
uses: stringbean/docker-healthcheck-action@v3
|
|
||||||
with:
|
|
||||||
container: trilium_local
|
|
||||||
wait-time: 50
|
|
||||||
require-status: running
|
|
||||||
require-healthy: true
|
|
||||||
|
|
||||||
# Print the entire log of the container thus far, regardless if the healthcheck failed or succeeded
|
|
||||||
- name: Print entire log
|
|
||||||
if: always()
|
|
||||||
run: journalctl -u docker CONTAINER_NAME=trilium_local --no-pager
|
|
||||||
53
.github/workflows/docker.yaml
vendored
Normal file
53
.github/workflows/docker.yaml
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
name: Publish Docker image
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: [v*]
|
||||||
|
jobs:
|
||||||
|
push_to_registries:
|
||||||
|
name: Push Docker image to multiple registries
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
- name: Docker meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v3
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
zadam/trilium
|
||||||
|
ghcr.io/zadam/trilium
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}-latest
|
||||||
|
type=match,pattern=(\d+.\d+).\d+\-beta,enable=${{ endsWith(github.ref, 'beta') }},group=1,suffix=-latest
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
with:
|
||||||
|
install: true
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
- name: Log in to GitHub Docker Registry
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Create server-package.json
|
||||||
|
run: cat package.json | grep -v electron > server-package.json
|
||||||
|
- name: Build and Push
|
||||||
|
uses: docker/build-push-action@v2.7.0
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6
|
||||||
|
push: true
|
||||||
|
cache-from: type=registry,ref=zadam/trilium:buildcache
|
||||||
|
cache-to: type=registry,ref=zadam/trilium:buildcache,mode=max
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
307
.github/workflows/main-docker.yml
vendored
307
.github/workflows/main-docker.yml
vendored
@@ -1,307 +0,0 @@
|
|||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- "main"
|
|
||||||
- "feature/update**"
|
|
||||||
- "feature/server_esm**"
|
|
||||||
paths-ignore:
|
|
||||||
- "docs/**"
|
|
||||||
- "bin/**"
|
|
||||||
tags:
|
|
||||||
- "v*"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
GHCR_REGISTRY: ghcr.io
|
|
||||||
DOCKERHUB_REGISTRY: docker.io
|
|
||||||
IMAGE_NAME: ${{ github.repository}}
|
|
||||||
TEST_TAG: ${{ github.repository}}:test
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test_docker:
|
|
||||||
name: Check Docker build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- dockerfile: Dockerfile.alpine
|
|
||||||
- dockerfile: Dockerfile
|
|
||||||
steps:
|
|
||||||
- name: Checkout the repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Set IMAGE_NAME to lowercase
|
|
||||||
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
|
|
||||||
- name: Set TEST_TAG to lowercase
|
|
||||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- name: Set up node & dependencies
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: "pnpm"
|
|
||||||
|
|
||||||
- name: Install npm dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Install Playwright Browsers
|
|
||||||
run: pnpm exec playwright install --with-deps
|
|
||||||
|
|
||||||
- name: Run the TypeScript build
|
|
||||||
run: pnpm run server:build
|
|
||||||
|
|
||||||
- name: Build and export to Docker
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: apps/server
|
|
||||||
file: apps/server/${{ matrix.dockerfile }}
|
|
||||||
load: true
|
|
||||||
tags: ${{ env.TEST_TAG }}
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
|
|
||||||
- name: Validate container run output
|
|
||||||
run: |
|
|
||||||
CONTAINER_ID=$(docker run -d --log-driver=journald --rm --network=host -e TRILIUM_PORT=8082 --volume ./apps/server/spec/db:/home/node/trilium-data --name trilium_local ${{ env.TEST_TAG }})
|
|
||||||
echo "Container ID: $CONTAINER_ID"
|
|
||||||
|
|
||||||
- name: Wait for the healthchecks to pass
|
|
||||||
uses: stringbean/docker-healthcheck-action@v3
|
|
||||||
with:
|
|
||||||
container: trilium_local
|
|
||||||
wait-time: 50
|
|
||||||
require-status: running
|
|
||||||
require-healthy: true
|
|
||||||
|
|
||||||
- name: Run Playwright tests
|
|
||||||
run: TRILIUM_DOCKER=1 TRILIUM_PORT=8082 pnpm --filter=server-e2e e2e
|
|
||||||
|
|
||||||
- name: Upload Playwright trace
|
|
||||||
if: failure()
|
|
||||||
uses: actions/upload-artifact@v5
|
|
||||||
with:
|
|
||||||
name: Playwright trace (${{ matrix.dockerfile }})
|
|
||||||
path: test-output/playwright/output
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v5
|
|
||||||
if: ${{ !cancelled() }}
|
|
||||||
with:
|
|
||||||
name: Playwright report (${{ matrix.dockerfile }})
|
|
||||||
path: playwright-report/
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
# Print the entire log of the container thus far, regardless if the healthcheck failed or succeeded
|
|
||||||
- name: Print entire log
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
journalctl -u docker CONTAINER_NAME=trilium_local --no-pager
|
|
||||||
|
|
||||||
build:
|
|
||||||
name: Build Docker images
|
|
||||||
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.legacy
|
|
||||||
platform: linux/arm/v7
|
|
||||||
image: ubuntu-24.04-arm
|
|
||||||
- dockerfile: Dockerfile.legacy
|
|
||||||
platform: linux/arm/v8
|
|
||||||
image: ubuntu-24.04-arm
|
|
||||||
runs-on: ${{ matrix.image }}
|
|
||||||
needs:
|
|
||||||
- test_docker
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
attestations: write
|
|
||||||
id-token: write
|
|
||||||
steps:
|
|
||||||
- name: Prepare
|
|
||||||
run: |
|
|
||||||
platform=${{ matrix.platform }}
|
|
||||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
|
||||||
- name: Set IMAGE_NAME to lowercase
|
|
||||||
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
|
|
||||||
- name: Set TEST_TAG to lowercase
|
|
||||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- name: Set up node & dependencies
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: 'pnpm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Update build info
|
|
||||||
run: pnpm run chore:update-build-info
|
|
||||||
|
|
||||||
- name: Run the TypeScript build
|
|
||||||
run: pnpm run server:build
|
|
||||||
|
|
||||||
- name: Docker meta
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
tags: |
|
|
||||||
type=ref,event=branch
|
|
||||||
type=ref,event=tag
|
|
||||||
type=sha
|
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Login to GHCR
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ${{ env.GHCR_REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ${{ env.DOCKERHUB_REGISTRY }}
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push by digest
|
|
||||||
id: build
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: apps/server
|
|
||||||
file: apps/server/${{ matrix.dockerfile }}
|
|
||||||
platforms: ${{ matrix.platform }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
outputs: type=image,name=${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
|
||||||
|
|
||||||
- name: Export digest
|
|
||||||
run: |
|
|
||||||
mkdir -p /tmp/digests
|
|
||||||
digest="${{ steps.build.outputs.digest }}"
|
|
||||||
touch "/tmp/digests/${digest#sha256:}"
|
|
||||||
|
|
||||||
- name: Upload digest
|
|
||||||
uses: actions/upload-artifact@v5
|
|
||||||
with:
|
|
||||||
name: digests-${{ env.PLATFORM_PAIR }}-${{ matrix.dockerfile }}
|
|
||||||
path: /tmp/digests/*
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
merge:
|
|
||||||
name: Merge manifest lists
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- build
|
|
||||||
steps:
|
|
||||||
- name: Download digests
|
|
||||||
uses: actions/download-artifact@v6
|
|
||||||
with:
|
|
||||||
path: /tmp/digests
|
|
||||||
pattern: digests-*
|
|
||||||
merge-multiple: true
|
|
||||||
- name: Set IMAGE_NAME to lowercase
|
|
||||||
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
|
|
||||||
- name: Set TEST_TAG to lowercase
|
|
||||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Docker meta
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
|
|
||||||
- name: Login to GHCR
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ${{ env.GHCR_REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ${{ env.DOCKERHUB_REGISTRY }}
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Create manifest list and push
|
|
||||||
working-directory: /tmp/digests
|
|
||||||
run: |
|
|
||||||
# Extract the branch or tag name from the ref
|
|
||||||
REF_NAME=$(echo "${GITHUB_REF}" | sed 's/refs\/heads\///' | sed 's/refs\/tags\///')
|
|
||||||
|
|
||||||
# Create and push the manifest list with both the branch/tag name and the commit SHA
|
|
||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
|
||||||
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME} \
|
|
||||||
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
|
||||||
|
|
||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
|
||||||
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME} \
|
|
||||||
$(printf '${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
|
||||||
|
|
||||||
# If the ref is a tag, also tag the image as stable as this is part of a 'release'
|
|
||||||
# and only go in the `if` if there is NOT a `-` in the tag's name, due to tagging of `-alpha`, `-beta`, etc...
|
|
||||||
if [[ "${GITHUB_REF}" == refs/tags/* && ! "${REF_NAME}" =~ - ]]; then
|
|
||||||
# First create stable tags
|
|
||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
|
||||||
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:stable \
|
|
||||||
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
|
||||||
|
|
||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
|
||||||
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:stable \
|
|
||||||
$(printf '${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
|
||||||
|
|
||||||
# Small delay to ensure stable tag is fully propagated
|
|
||||||
sleep 5
|
|
||||||
|
|
||||||
# Now update latest tags
|
|
||||||
docker buildx imagetools create \
|
|
||||||
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
|
|
||||||
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:stable
|
|
||||||
|
|
||||||
docker buildx imagetools create \
|
|
||||||
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
|
|
||||||
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:stable
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Inspect image
|
|
||||||
run: |
|
|
||||||
docker buildx imagetools inspect ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
|
|
||||||
docker buildx imagetools inspect ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
|
|
||||||
130
.github/workflows/nightly.yml
vendored
130
.github/workflows/nightly.yml
vendored
@@ -1,130 +0,0 @@
|
|||||||
name: Nightly Release
|
|
||||||
on:
|
|
||||||
# This can be used to automatically publish nightlies at UTC nighttime
|
|
||||||
schedule:
|
|
||||||
- cron: "0 2 * * *" # run at 2 AM UTC
|
|
||||||
# This can be used to allow manually triggering nightlies from the web interface
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- renovate/electron-forge*
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/build-electron/*
|
|
||||||
- .github/workflows/nightly.yml
|
|
||||||
- forge.config.ts
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
GITHUB_RELEASE_ID: 179589950
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
nightly-electron:
|
|
||||||
if: github.repository == ${{ vars.REPO_MAIN }}
|
|
||||||
name: Deploy nightly
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
arch: [x64, arm64]
|
|
||||||
os:
|
|
||||||
- name: macos
|
|
||||||
image: macos-latest
|
|
||||||
shell: bash
|
|
||||||
forge_platform: darwin
|
|
||||||
- name: linux
|
|
||||||
image: ubuntu-22.04
|
|
||||||
shell: bash
|
|
||||||
forge_platform: linux
|
|
||||||
- name: windows
|
|
||||||
image: win-signing
|
|
||||||
shell: cmd
|
|
||||||
forge_platform: win32
|
|
||||||
runs-on: ${{ matrix.os.image }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- name: Set up node & dependencies
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: 'pnpm'
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
- name: 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 }}
|
|
||||||
shell: ${{ matrix.os.shell }}
|
|
||||||
forge_platform: ${{ matrix.os.forge_platform }}
|
|
||||||
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 }}
|
|
||||||
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
|
|
||||||
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
|
|
||||||
|
|
||||||
- name: Publish release
|
|
||||||
uses: softprops/action-gh-release@v2.4.2
|
|
||||||
if: ${{ github.event_name != 'pull_request' }}
|
|
||||||
with:
|
|
||||||
make_latest: false
|
|
||||||
prerelease: true
|
|
||||||
draft: false
|
|
||||||
fail_on_unmatched_files: true
|
|
||||||
files: apps/desktop/upload/*.*
|
|
||||||
tag_name: nightly
|
|
||||||
name: Nightly Build
|
|
||||||
|
|
||||||
- name: Publish artifacts
|
|
||||||
uses: actions/upload-artifact@v5
|
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
with:
|
|
||||||
name: TriliumNotes ${{ matrix.os.name }} ${{ matrix.arch }}
|
|
||||||
path: apps/desktop/upload
|
|
||||||
|
|
||||||
nightly-server:
|
|
||||||
if: github.repository == ${{ vars.REPO_MAIN }}
|
|
||||||
name: Deploy server nightly
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
arch: [x64, arm64]
|
|
||||||
include:
|
|
||||||
- arch: x64
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
- arch: arm64
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
runs-on: ${{ matrix.runs-on }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Run the build
|
|
||||||
uses: ./.github/actions/build-server
|
|
||||||
with:
|
|
||||||
os: linux
|
|
||||||
arch: ${{ matrix.arch }}
|
|
||||||
|
|
||||||
- name: Publish release
|
|
||||||
uses: softprops/action-gh-release@v2.4.2
|
|
||||||
if: ${{ github.event_name != 'pull_request' }}
|
|
||||||
with:
|
|
||||||
make_latest: false
|
|
||||||
prerelease: true
|
|
||||||
draft: false
|
|
||||||
fail_on_unmatched_files: true
|
|
||||||
files: upload/*.*
|
|
||||||
tag_name: nightly
|
|
||||||
name: Nightly Build
|
|
||||||
41
.github/workflows/playwright.yml
vendored
41
.github/workflows/playwright.yml
vendored
@@ -1,41 +0,0 @@
|
|||||||
name: playwright
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths-ignore:
|
|
||||||
- "apps/website/**"
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
main:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
filter: tree:0
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: 'pnpm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
- run: pnpm exec playwright install --with-deps
|
|
||||||
|
|
||||||
- run: pnpm --filter server-e2e e2e
|
|
||||||
|
|
||||||
- name: Upload test report
|
|
||||||
if: failure()
|
|
||||||
uses: actions/upload-artifact@v5
|
|
||||||
with:
|
|
||||||
name: e2e report
|
|
||||||
path: apps/server-e2e/test-output
|
|
||||||
20
.github/workflows/release-winget.yml
vendored
20
.github/workflows/release-winget.yml
vendored
@@ -1,20 +0,0 @@
|
|||||||
name: Release to winget
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [ published ]
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
release_tag:
|
|
||||||
description: 'Git tag to release from'
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
jobs:
|
|
||||||
release-winget:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Publish to WinGet
|
|
||||||
uses: vedantmgoyal9/winget-releaser@main
|
|
||||||
with:
|
|
||||||
identifier: TriliumNext.Notes
|
|
||||||
token: ${{ secrets.WINGET_PAT }}
|
|
||||||
release-tag: ${{ github.event.inputs.release_tag || github.event.release.tag_name }}
|
|
||||||
139
.github/workflows/release.yml
vendored
139
.github/workflows/release.yml
vendored
@@ -1,139 +0,0 @@
|
|||||||
name: Release
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*"
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
discussions: write
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
make-electron:
|
|
||||||
name: Make Electron
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
arch: [x64, arm64]
|
|
||||||
os:
|
|
||||||
- name: macos
|
|
||||||
image: macos-latest
|
|
||||||
shell: bash
|
|
||||||
forge_platform: darwin
|
|
||||||
- name: linux
|
|
||||||
image: ubuntu-22.04
|
|
||||||
shell: bash
|
|
||||||
forge_platform: linux
|
|
||||||
- name: windows
|
|
||||||
image: win-signing
|
|
||||||
shell: cmd
|
|
||||||
forge_platform: win32
|
|
||||||
# Exclude ARM64 Linux from default matrix to use native runner
|
|
||||||
exclude:
|
|
||||||
- arch: arm64
|
|
||||||
os:
|
|
||||||
name: linux
|
|
||||||
# Add ARM64 Linux with native ubuntu-24.04-arm runner for better-sqlite3 compatibility
|
|
||||||
include:
|
|
||||||
- arch: arm64
|
|
||||||
os:
|
|
||||||
name: linux
|
|
||||||
image: ubuntu-24.04-arm
|
|
||||||
shell: bash
|
|
||||||
forge_platform: linux
|
|
||||||
runs-on: ${{ matrix.os.image }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- name: Set up node & dependencies
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: 'pnpm'
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
- name: Run the build
|
|
||||||
uses: ./.github/actions/build-electron
|
|
||||||
with:
|
|
||||||
os: ${{ matrix.os.name }}
|
|
||||||
arch: ${{ matrix.arch }}
|
|
||||||
shell: ${{ matrix.os.shell }}
|
|
||||||
forge_platform: ${{ matrix.os.forge_platform }}
|
|
||||||
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 }}
|
|
||||||
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
|
|
||||||
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
|
|
||||||
|
|
||||||
- name: Upload the artifact
|
|
||||||
uses: actions/upload-artifact@v5
|
|
||||||
with:
|
|
||||||
name: release-desktop-${{ matrix.os.name }}-${{ matrix.arch }}
|
|
||||||
path: apps/desktop/upload/*.*
|
|
||||||
|
|
||||||
build_server:
|
|
||||||
name: Build Linux Server
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
arch: [x64, arm64]
|
|
||||||
include:
|
|
||||||
- arch: x64
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
- arch: arm64
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
runs-on: ${{ matrix.runs-on }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Run the build
|
|
||||||
uses: ./.github/actions/build-server
|
|
||||||
with:
|
|
||||||
os: linux
|
|
||||||
arch: ${{ matrix.arch }}
|
|
||||||
|
|
||||||
- name: Upload the artifact
|
|
||||||
uses: actions/upload-artifact@v5
|
|
||||||
with:
|
|
||||||
name: release-server-linux-${{ matrix.arch }}
|
|
||||||
path: upload/*.*
|
|
||||||
|
|
||||||
publish_release:
|
|
||||||
name: Publish release
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- make-electron
|
|
||||||
- build_server
|
|
||||||
steps:
|
|
||||||
- run: mkdir upload
|
|
||||||
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
sparse-checkout: |
|
|
||||||
docs/Release Notes
|
|
||||||
|
|
||||||
- name: Download all artifacts
|
|
||||||
uses: actions/download-artifact@v6
|
|
||||||
with:
|
|
||||||
merge-multiple: true
|
|
||||||
pattern: release-*
|
|
||||||
path: upload
|
|
||||||
|
|
||||||
- name: Publish stable release
|
|
||||||
uses: softprops/action-gh-release@v2.4.2
|
|
||||||
with:
|
|
||||||
draft: false
|
|
||||||
body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md
|
|
||||||
fail_on_unmatched_files: true
|
|
||||||
files: upload/*.*
|
|
||||||
discussion_category_name: Releases
|
|
||||||
make_latest: ${{ !contains(github.ref, 'rc') }}
|
|
||||||
prerelease: ${{ contains(github.ref, 'rc') }}
|
|
||||||
token: ${{ secrets.RELEASE_PAT }}
|
|
||||||
11
.github/workflows/unblock_signing.yml
vendored
11
.github/workflows/unblock_signing.yml
vendored
@@ -1,11 +0,0 @@
|
|||||||
name: Unblock signing
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
unblock-win-signing:
|
|
||||||
runs-on: win-signing
|
|
||||||
steps:
|
|
||||||
- run: |
|
|
||||||
cat ${{ vars.WINDOWS_SIGN_ERROR_LOG }}
|
|
||||||
rm ${{ vars.WINDOWS_SIGN_ERROR_LOG }}
|
|
||||||
51
.github/workflows/website.yml
vendored
51
.github/workflows/website.yml
vendored
@@ -1,51 +0,0 @@
|
|||||||
name: Deploy website
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- "apps/website/**"
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- "apps/website/**"
|
|
||||||
|
|
||||||
release:
|
|
||||||
types: [ released ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-deploy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Build & deploy website
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
deployments: write
|
|
||||||
pull-requests: write # For PR preview comments
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- name: Set up node & dependencies
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: "pnpm"
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --filter website --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Build the website
|
|
||||||
run: pnpm website:build
|
|
||||||
|
|
||||||
- name: Deploy
|
|
||||||
uses: ./.github/actions/deploy-to-cloudflare-pages
|
|
||||||
with:
|
|
||||||
project_name: "trilium-homepage"
|
|
||||||
comment_body: "📚 Website preview is ready"
|
|
||||||
production_url: "https://triliumnotes.org"
|
|
||||||
deploy_dir: "apps/website/dist"
|
|
||||||
cloudflare_api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
||||||
cloudflare_account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
58
.gitignore
vendored
58
.gitignore
vendored
@@ -1,51 +1,11 @@
|
|||||||
# See https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
.DS_Store
|
||||||
/.cache
|
node_modules/
|
||||||
|
dist/
|
||||||
# compiled output
|
src/public/app-dist/
|
||||||
dist
|
|
||||||
tmp
|
|
||||||
out-tsc
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
node_modules
|
|
||||||
|
|
||||||
# IDEs and editors
|
|
||||||
/.idea
|
|
||||||
.idea
|
|
||||||
.project
|
|
||||||
.classpath
|
|
||||||
.c9/
|
|
||||||
*.launch
|
|
||||||
.settings/
|
|
||||||
*.sublime-workspace
|
|
||||||
|
|
||||||
# misc
|
|
||||||
/.sass-cache
|
|
||||||
/connect.lock
|
|
||||||
/coverage
|
|
||||||
/libpeerconnection.log
|
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
testem.log
|
*.db
|
||||||
/typings
|
config.ini
|
||||||
|
cert.key
|
||||||
# System Files
|
cert.crt
|
||||||
.DS_Store
|
server-package.json
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
vite.config.*.timestamp*
|
|
||||||
vitest.config.*.timestamp*
|
|
||||||
test-output
|
|
||||||
|
|
||||||
apps/*/data*
|
|
||||||
apps/*/out
|
|
||||||
upload
|
|
||||||
|
|
||||||
.rollup.cache
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
/result
|
|
||||||
.svelte-kit
|
|
||||||
|
|
||||||
# docs
|
|
||||||
site/
|
|
||||||
15
.gitpod.dockerfile
Normal file
15
.gitpod.dockerfile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
FROM gitpod/workspace-full
|
||||||
|
|
||||||
|
RUN sudo apt-get update \
|
||||||
|
&& sudo apt-get install -yq --no-install-recommends \
|
||||||
|
libpng16-16 \
|
||||||
|
libpng-dev \
|
||||||
|
pkg-config \
|
||||||
|
autoconf \
|
||||||
|
libtool \
|
||||||
|
build-essential \
|
||||||
|
nasm \
|
||||||
|
libx11-dev \
|
||||||
|
libxkbfile-dev \
|
||||||
|
&& sudo rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
11
.gitpod.yml
Normal file
11
.gitpod.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
image:
|
||||||
|
file: .gitpod.dockerfile
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- before: nvm install 16.13.1 && nvm use 16.13.1
|
||||||
|
init: npm install
|
||||||
|
command: npm run start-server
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- port: 8080
|
||||||
|
onOpen: open-preview
|
||||||
6
.idea/.gitignore
generated
vendored
Normal file
6
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/workspace.xml
|
||||||
|
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources.local.xml
|
||||||
|
/dataSources/
|
||||||
13
.idea/codeStyles/Project.xml
generated
Normal file
13
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<option name="OTHER_INDENT_OPTIONS">
|
||||||
|
<value>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<JSCodeStyleSettings version="0">
|
||||||
|
<option name="USE_EXPLICIT_JS_EXTENSION" value="TRUE" />
|
||||||
|
</JSCodeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
||||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
12
.idea/dataSources.xml
generated
Normal file
12
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="SQLite - document.db" uuid="30cef30d-e704-484d-a4ca-5d3bfc2ece63">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/../trilium-data/document.db</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
4
.idea/encodings.xml
generated
Normal file
4
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
|
||||||
|
</project>
|
||||||
11
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
11
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="JSUnfilteredForInLoop" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||||
|
<option name="processCode" value="true" />
|
||||||
|
<option name="processLiterals" value="true" />
|
||||||
|
<option name="processComments" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
6
.idea/jsLibraryMappings.xml
generated
Normal file
6
.idea/jsLibraryMappings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptLibraryMappings">
|
||||||
|
<includedPredefinedLibrary name="Node.js Core" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
9
.idea/jsLinters/jslint.xml
generated
Normal file
9
.idea/jsLinters/jslint.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JSLintConfiguration">
|
||||||
|
<option devel="true" />
|
||||||
|
<option es6="true" />
|
||||||
|
<option maxerr="50" />
|
||||||
|
<option node="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
9
.idea/misc.xml
generated
Normal file
9
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" project-jdk-name="openjdk-16" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/trilium.iml" filepath="$PROJECT_DIR$/trilium.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
7
.idea/sqldialects.xml
generated
Normal file
7
.idea/sqldialects.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="SqlDialectMappings">
|
||||||
|
<file url="file://$PROJECT_DIR$" dialect="SQLite" />
|
||||||
|
<file url="PROJECT" dialect="SQLite" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
15
.vscode/extensions.json
vendored
15
.vscode/extensions.json
vendored
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"recommendations": [
|
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"editorconfig.editorconfig",
|
|
||||||
"lokalise.i18n-ally",
|
|
||||||
"ms-azuretools.vscode-docker",
|
|
||||||
"ms-playwright.playwright",
|
|
||||||
"redhat.vscode-yaml",
|
|
||||||
"tobermory.es6-string-html",
|
|
||||||
"vitest.explorer",
|
|
||||||
"yzhang.markdown-all-in-one",
|
|
||||||
"svelte.svelte-vscode",
|
|
||||||
"bradlc.vscode-tailwindcss"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
36
.vscode/i18n-ally-custom-framework.yml
vendored
36
.vscode/i18n-ally-custom-framework.yml
vendored
@@ -1,36 +0,0 @@
|
|||||||
# An array of strings which contain Language Ids defined by VS Code
|
|
||||||
# You can check available language ids here: https://code.visualstudio.com/docs/languages/identifiers
|
|
||||||
languageIds:
|
|
||||||
- javascript
|
|
||||||
- typescript
|
|
||||||
- typescriptreact
|
|
||||||
- html
|
|
||||||
|
|
||||||
# An array of RegExes to find the key usage. **The key should be captured in the first match group**.
|
|
||||||
# You should unescape RegEx strings in order to fit in the YAML file
|
|
||||||
# To help with this, you can use https://www.freeformatter.com/json-escape.html
|
|
||||||
usageMatchRegex:
|
|
||||||
# The following example shows how to detect `t("your.i18n.keys")`
|
|
||||||
# the `{key}` will be placed by a proper keypath matching regex,
|
|
||||||
# you can ignore it and use your own matching rules as well
|
|
||||||
- "[^\\w\\d]t\\(['\"`]({key})['\"`]"
|
|
||||||
- <Trans\s*i18nKey="({key})"[^>]*>
|
|
||||||
|
|
||||||
# A RegEx to set a custom scope range. This scope will be used as a prefix when detecting keys
|
|
||||||
# and works like how the i18next framework identifies the namespace scope from the
|
|
||||||
# useTranslation() hook.
|
|
||||||
# You should unescape RegEx strings in order to fit in the YAML file
|
|
||||||
# To help with this, you can use https://www.freeformatter.com/json-escape.html
|
|
||||||
scopeRangeRegex: "useTranslation\\(\\s*\\[?\\s*['\"`](.*?)['\"`]"
|
|
||||||
|
|
||||||
# An array of strings containing refactor templates.
|
|
||||||
# The "$1" will be replaced by the keypath specified.
|
|
||||||
refactorTemplates:
|
|
||||||
- t("$1")
|
|
||||||
- {t("$1")}
|
|
||||||
- ${t("$1")}
|
|
||||||
- <%= t("$1") %>
|
|
||||||
|
|
||||||
|
|
||||||
# If set to true, only enables this custom framework (will disable all built-in frameworks)
|
|
||||||
monopoly: true
|
|
||||||
18
.vscode/launch.json
vendored
Normal file
18
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "start-server",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"TRILIUM_ENV": "dev"
|
||||||
|
},
|
||||||
|
"outputCapture": "std",
|
||||||
|
"program": "${workspaceFolder}/src/www"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
40
.vscode/settings.json
vendored
40
.vscode/settings.json
vendored
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"editor.formatOnSave": false,
|
|
||||||
"files.eol": "\n",
|
|
||||||
"i18n-ally.sourceLanguage": "en",
|
|
||||||
"i18n-ally.keystyle": "nested",
|
|
||||||
"i18n-ally.localesPaths": [
|
|
||||||
"apps/server/src/assets/translations",
|
|
||||||
"apps/client/src/translations",
|
|
||||||
"apps/website/public/translations"
|
|
||||||
],
|
|
||||||
"npm.exclude": [
|
|
||||||
"**/dist",
|
|
||||||
],
|
|
||||||
"[jsonc]": {
|
|
||||||
"editor.defaultFormatter": "vscode.json-language-features"
|
|
||||||
},
|
|
||||||
"[javascript]": {
|
|
||||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
|
||||||
},
|
|
||||||
"[typescript]": {
|
|
||||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
|
||||||
},
|
|
||||||
"[css]": {
|
|
||||||
"editor.defaultFormatter": "vscode.css-language-features"
|
|
||||||
},
|
|
||||||
"github-actions.workflows.pinned.workflows": [
|
|
||||||
".github/workflows/nightly.yml"
|
|
||||||
],
|
|
||||||
"typescript.validate.enable": true,
|
|
||||||
"typescript.tsserver.experimental.enableProjectDiagnostics": true,
|
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
|
||||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
|
||||||
"search.exclude": {
|
|
||||||
"**/node_modules": true,
|
|
||||||
"docs/**/*.html": true,
|
|
||||||
"docs/**/*.png": true,
|
|
||||||
"apps/server/src/assets/doc_notes/**": true,
|
|
||||||
"apps/edit-docs/demo/**": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
.vscode/snippets.code-snippets
vendored
29
.vscode/snippets.code-snippets
vendored
@@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
// Place your Notes workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
|
|
||||||
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
|
|
||||||
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
|
|
||||||
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
|
|
||||||
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
|
|
||||||
// Placeholders with the same ids are connected.
|
|
||||||
// Example:
|
|
||||||
// "Print to console": {
|
|
||||||
// "scope": "javascript,typescript",
|
|
||||||
// "prefix": "log",
|
|
||||||
// "body": [
|
|
||||||
// "console.log('$1');",
|
|
||||||
// "$2"
|
|
||||||
// ],
|
|
||||||
// "description": "Log output to console"
|
|
||||||
// }
|
|
||||||
|
|
||||||
"JQuery HTMLElement field": {
|
|
||||||
"scope": "typescript",
|
|
||||||
"prefix": "jqf",
|
|
||||||
"body": ["private $${1:name}!: JQuery<HTMLElement>;"]
|
|
||||||
},
|
|
||||||
"region": {
|
|
||||||
"scope": "css",
|
|
||||||
"prefix": "region",
|
|
||||||
"body": ["/* #region ${1:name} */\n$0\n/* #endregion */"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
152
CLAUDE.md
152
CLAUDE.md
@@ -1,152 +0,0 @@
|
|||||||
# CLAUDE.md
|
|
||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Trilium Notes is a hierarchical note-taking application with advanced features like synchronization, scripting, and rich text editing. It's built as a TypeScript monorepo using pnpm, with multiple applications and shared packages.
|
|
||||||
|
|
||||||
## Development Commands
|
|
||||||
|
|
||||||
### Setup
|
|
||||||
- `pnpm install` - Install all dependencies
|
|
||||||
- `corepack enable` - Enable pnpm if not available
|
|
||||||
|
|
||||||
### Running Applications
|
|
||||||
- `pnpm run server:start` - Start development server (http://localhost:8080)
|
|
||||||
- `pnpm run server:start-prod` - Run server in production mode
|
|
||||||
|
|
||||||
### Building
|
|
||||||
- `pnpm run client:build` - Build client application
|
|
||||||
- `pnpm run server:build` - Build server application
|
|
||||||
- `pnpm run electron:build` - Build desktop application
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- `pnpm test:all` - Run all tests (parallel + sequential)
|
|
||||||
- `pnpm test:parallel` - Run tests that can run in parallel
|
|
||||||
- `pnpm test:sequential` - Run tests that must run sequentially (server, ckeditor5-mermaid, ckeditor5-math)
|
|
||||||
- `pnpm coverage` - Generate coverage reports
|
|
||||||
|
|
||||||
## Architecture Overview
|
|
||||||
|
|
||||||
### Monorepo Structure
|
|
||||||
- **apps/**: Runnable applications
|
|
||||||
- `client/` - Frontend application (shared by server and desktop)
|
|
||||||
- `server/` - Node.js server with web interface
|
|
||||||
- `desktop/` - Electron desktop application
|
|
||||||
- `web-clipper/` - Browser extension for saving web content
|
|
||||||
- Additional tools: `db-compare`, `dump-db`, `edit-docs`
|
|
||||||
|
|
||||||
- **packages/**: Shared libraries
|
|
||||||
- `commons/` - Shared interfaces and utilities
|
|
||||||
- `ckeditor5/` - Custom rich text editor with Trilium-specific plugins
|
|
||||||
- `codemirror/` - Code editor customizations
|
|
||||||
- `highlightjs/` - Syntax highlighting
|
|
||||||
- Custom CKEditor plugins: `ckeditor5-admonition`, `ckeditor5-footnotes`, `ckeditor5-math`, `ckeditor5-mermaid`
|
|
||||||
|
|
||||||
### Core Architecture Patterns
|
|
||||||
|
|
||||||
#### Three-Layer Cache System
|
|
||||||
- **Becca** (Backend Cache): Server-side entity cache (`apps/server/src/becca/`)
|
|
||||||
- **Froca** (Frontend Cache): Client-side mirror of backend data (`apps/client/src/services/froca.ts`)
|
|
||||||
- **Shaca** (Share Cache): Optimized cache for shared/published notes (`apps/server/src/share/`)
|
|
||||||
|
|
||||||
#### Entity System
|
|
||||||
Core entities are defined in `apps/server/src/becca/entities/`:
|
|
||||||
- `BNote` - Notes with content and metadata
|
|
||||||
- `BBranch` - Hierarchical relationships between notes (allows multiple parents)
|
|
||||||
- `BAttribute` - Key-value metadata attached to notes
|
|
||||||
- `BRevision` - Note version history
|
|
||||||
- `BOption` - Application configuration
|
|
||||||
|
|
||||||
#### Widget-Based UI
|
|
||||||
Frontend uses a widget system (`apps/client/src/widgets/`):
|
|
||||||
- `BasicWidget` - Base class for all UI components
|
|
||||||
- `NoteContextAwareWidget` - Widgets that respond to note changes
|
|
||||||
- `RightPanelWidget` - Widgets displayed in the right panel
|
|
||||||
- Type-specific widgets in `type_widgets/` directory
|
|
||||||
|
|
||||||
#### API Architecture
|
|
||||||
- **Internal API**: REST endpoints in `apps/server/src/routes/api/`
|
|
||||||
- **ETAPI**: External API for third-party integrations (`apps/server/src/etapi/`)
|
|
||||||
- **WebSocket**: Real-time synchronization (`apps/server/src/services/ws.ts`)
|
|
||||||
|
|
||||||
### Key Files for Understanding Architecture
|
|
||||||
|
|
||||||
1. **Application Entry Points**:
|
|
||||||
- `apps/server/src/main.ts` - Server startup
|
|
||||||
- `apps/client/src/desktop.ts` - Client initialization
|
|
||||||
|
|
||||||
2. **Core Services**:
|
|
||||||
- `apps/server/src/becca/becca.ts` - Backend data management
|
|
||||||
- `apps/client/src/services/froca.ts` - Frontend data synchronization
|
|
||||||
- `apps/server/src/services/backend_script_api.ts` - Scripting API
|
|
||||||
|
|
||||||
3. **Database Schema**:
|
|
||||||
- `apps/server/src/assets/db/schema.sql` - Core database structure
|
|
||||||
|
|
||||||
4. **Configuration**:
|
|
||||||
- `package.json` - Project dependencies and scripts
|
|
||||||
|
|
||||||
## Note Types and Features
|
|
||||||
|
|
||||||
Trilium supports multiple note types, each with specialized widgets:
|
|
||||||
- **Text**: Rich text with CKEditor5 (markdown import/export)
|
|
||||||
- **Code**: Syntax-highlighted code editing with CodeMirror
|
|
||||||
- **File**: Binary file attachments
|
|
||||||
- **Image**: Image display with editing capabilities
|
|
||||||
- **Canvas**: Drawing/diagramming with Excalidraw
|
|
||||||
- **Mermaid**: Diagram generation
|
|
||||||
- **Relation Map**: Visual note relationship mapping
|
|
||||||
- **Web View**: Embedded web pages
|
|
||||||
- **Doc/Book**: Hierarchical documentation structure
|
|
||||||
|
|
||||||
## Development Guidelines
|
|
||||||
|
|
||||||
### Testing Strategy
|
|
||||||
- Server tests run sequentially due to shared database
|
|
||||||
- Client tests can run in parallel
|
|
||||||
- E2E tests use Playwright for both server and desktop apps
|
|
||||||
- Build validation tests check artifact integrity
|
|
||||||
|
|
||||||
### Scripting System
|
|
||||||
Trilium provides powerful user scripting capabilities:
|
|
||||||
- Frontend scripts run in browser context
|
|
||||||
- Backend scripts run in Node.js context with full API access
|
|
||||||
- Script API documentation available in `docs/Script API/`
|
|
||||||
|
|
||||||
### Internationalization
|
|
||||||
- Translation files in `apps/client/src/translations/`
|
|
||||||
- Supported languages: English, German, Spanish, French, Romanian, Chinese
|
|
||||||
|
|
||||||
### Security Considerations
|
|
||||||
- Per-note encryption with granular protected sessions
|
|
||||||
- CSRF protection for API endpoints
|
|
||||||
- OpenID and TOTP authentication support
|
|
||||||
- Sanitization of user-generated content
|
|
||||||
|
|
||||||
## Common Development Tasks
|
|
||||||
|
|
||||||
### Adding New Note Types
|
|
||||||
1. Create widget in `apps/client/src/widgets/type_widgets/`
|
|
||||||
2. Register in `apps/client/src/services/note_types.ts`
|
|
||||||
3. Add backend handling in `apps/server/src/services/notes.ts`
|
|
||||||
|
|
||||||
### Extending Search
|
|
||||||
- Search expressions handled in `apps/server/src/services/search/`
|
|
||||||
- Add new search operators in search context files
|
|
||||||
|
|
||||||
### Custom CKEditor Plugins
|
|
||||||
- Create new package in `packages/` following existing plugin structure
|
|
||||||
- Register in `packages/ckeditor5/src/plugins.ts`
|
|
||||||
|
|
||||||
### Database Migrations
|
|
||||||
- Add migration scripts in `apps/server/src/migrations/`
|
|
||||||
- Update schema in `apps/server/src/assets/db/schema.sql`
|
|
||||||
|
|
||||||
## Build System Notes
|
|
||||||
- Uses pnpm for monorepo management
|
|
||||||
- Vite for fast development builds
|
|
||||||
- ESBuild for production optimization
|
|
||||||
- pnpm workspaces for dependency management
|
|
||||||
- Docker support with multi-stage builds
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Please treat each other with respect and understanding.
|
|
||||||
29
Dockerfile
Normal file
29
Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
FROM node:16.13.1-alpine
|
||||||
|
|
||||||
|
# Create app directory
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
COPY server-package.json package.json
|
||||||
|
|
||||||
|
# Install app dependencies
|
||||||
|
RUN set -x \
|
||||||
|
&& apk add --no-cache --virtual .build-dependencies \
|
||||||
|
autoconf \
|
||||||
|
automake \
|
||||||
|
g++ \
|
||||||
|
gcc \
|
||||||
|
libtool \
|
||||||
|
make \
|
||||||
|
nasm \
|
||||||
|
libpng-dev \
|
||||||
|
python3 \
|
||||||
|
&& npm install --production \
|
||||||
|
&& apk del .build-dependencies
|
||||||
|
|
||||||
|
# Bundle app source
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
USER node
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
CMD [ "node", "./src/www" ]
|
||||||
62
README-ZH_CN.md
Normal file
62
README-ZH_CN.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Trilium笔记
|
||||||
|
|
||||||
|
[English](https://github.com/zadam/trilium/blob/master/README.md) | [Chinese](https://github.com/zadam/trilium/blob/master/README-ZH_CN.md) | [Russian](https://github.com/zadam/trilium/blob/master/README.ru.md)
|
||||||
|
|
||||||
|
[](https://gitter.im/trilium-notes/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
Trilium Notes是一个分层的笔记应用程序,专注于建立大型个人知识库。请参阅[屏幕截图](https://github.com/zadam/trilium/wiki/Screenshot-tour)以快速了解:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 特性
|
||||||
|
|
||||||
|
* 笔记可以排列成任意深的树。单个笔记可以放在树中的多个位置(请参阅[克隆](https://github.com/zadam/trilium/wiki/Cloning-notes))
|
||||||
|
* 丰富的所见即所得笔记编辑功能,包括带有markdown[自动格式化功能的](https://github.com/zadam/trilium/wiki/Text-notes#autoformat)表格,图像和[数学](https://github.com/zadam/trilium/wiki/Text-notes#math-support)
|
||||||
|
* 支持编辑[使用源代码的笔记](https://github.com/zadam/trilium/wiki/Code-notes),包括语法高亮显示
|
||||||
|
* 笔记之间快速[导航](https://github.com/zadam/trilium/wiki/Note-navigation),全文搜索和[笔记挂起](https://github.com/zadam/trilium/wiki/Note-hoisting)
|
||||||
|
* 无缝[笔记版本控制](https://github.com/zadam/trilium/wiki/Note-revisions)
|
||||||
|
* 笔记[属性](https://github.com/zadam/trilium/wiki/Attributes)可用于笔记组织,查询和高级[脚本编写](https://github.com/zadam/trilium/wiki/Scripts)
|
||||||
|
* [同步](https://github.com/zadam/trilium/wiki/Synchronization)与自托管同步服务器
|
||||||
|
* 具有按笔记粒度的强大的[笔记加密](https://github.com/zadam/trilium/wiki/Protected-notes)
|
||||||
|
* [关系图](https://github.com/zadam/trilium/wiki/Relation-map)和[链接图](https://github.com/zadam/trilium/wiki/Link-map),用于可视化笔记及其关系
|
||||||
|
* [脚本](https://github.com/zadam/trilium/wiki/Scripts)-请参阅[高级展示](https://github.com/zadam/trilium/wiki/Advanced-showcases)
|
||||||
|
* 可用性和性能均能很好地扩展至超过10万个笔记
|
||||||
|
* 针对智能手机和平板电脑进行触摸优化的[移动前端](https://github.com/zadam/trilium/wiki/Mobile-frontend)
|
||||||
|
* [夜间主题](https://github.com/zadam/trilium/wiki/Themes)
|
||||||
|
* [Evernote](https://github.com/zadam/trilium/wiki/Evernote-import)和[Markdown导入导出](https://github.com/zadam/trilium/wiki/Markdown)
|
||||||
|
* [Web Clipper](https://github.com/zadam/trilium/wiki/Web-clipper)可轻松保存Web内容
|
||||||
|
|
||||||
|
## 构建
|
||||||
|
|
||||||
|
Trilium是作为桌面应用程序(Linux和Windows)或服务器上托管的Web应用程序(Linux)提供的。Mac OS桌面版本可用,但[不受支持](https://github.com/zadam/trilium/wiki/FAQ#mac-os-support)。
|
||||||
|
|
||||||
|
* 如果要在桌面上使用Trilium,请从[最新版本](https://github.com/zadam/trilium/releases/latest)下载适用于您平台的二进制[版本](https://github.com/zadam/trilium/releases/latest),解压缩该软件包并运行`trilium`可执行文件。
|
||||||
|
* 如果要在服务器上安装Trilium,请遵循[此页面](https://github.com/zadam/trilium/wiki/Server-installation)。
|
||||||
|
* 当前仅支持(经过测试)最新的Chrome和Firefox浏览器。
|
||||||
|
|
||||||
|
## 文档
|
||||||
|
|
||||||
|
[有关文档页面的完整列表,请参见Wiki。](https://github.com/zadam/trilium/wiki/)
|
||||||
|
|
||||||
|
[中文Wiki在这里](https://github.com/baddate/trilium/wiki/)
|
||||||
|
|
||||||
|
您还可以阅读[个人知识库模式](https://github.com/zadam/trilium/wiki/Patterns-of-personal-knowledge-base),以获取有关如何使用Trilium的灵感。
|
||||||
|
|
||||||
|
## 贡献
|
||||||
|
|
||||||
|
使用基于浏览器的开发环境
|
||||||
|
|
||||||
|
[](https://gitpod.io/#https://github.com/zadam/trilium)
|
||||||
|
|
||||||
|
或在本地克隆并运行
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
npm run start-server
|
||||||
|
```
|
||||||
|
|
||||||
|
## 致谢
|
||||||
|
|
||||||
|
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - 市场上最好的所见即所得编辑器,互动性强且聆听能力强的团队
|
||||||
|
* [FancyTree](https://github.com/mar10/fancytree) - 一个非常丰富的关于树的库,强大的没有对手。没有它,Trilium Notes将不会如此。
|
||||||
|
* [CodeMirror](https://github.com/codemirror/CodeMirror) - 支持大量语言的代码编辑器
|
||||||
|
* [jsPlumb](https://github.com/jsplumb/jsplumb)强大的可视化连接库。- 用于[关系图](https://github.com/zadam/trilium/wiki/Relation-map)和[链接图](https://github.com/zadam/trilium/wiki/Link-map)
|
||||||
235
README.md
235
README.md
@@ -1,218 +1,63 @@
|
|||||||
<div align="center">
|
|
||||||
<sup>Special thanks to:</sup><br />
|
|
||||||
<a href="https://go.warp.dev/Trilium" target="_blank">
|
|
||||||
<img alt="Warp sponsorship" width="400" src="https://github.com/warpdotdev/brand-assets/blob/main/Github/Sponsor/Warp-Github-LG-03.png"><br />
|
|
||||||
Warp, built for coding with multiple AI agents<br />
|
|
||||||
</a>
|
|
||||||
<sup>Available for macOS, Linux and Windows</sup>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
# Trilium Notes
|
# Trilium Notes
|
||||||
|
|
||||||
 
|
[English](https://github.com/zadam/trilium/blob/master/README.md) | [Chinese](https://github.com/zadam/trilium/blob/master/README-ZH_CN.md) | [Russian](https://github.com/zadam/trilium/blob/master/README.ru.md)
|
||||||

|
|
||||||

|
|
||||||
[](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp) [](https://hosted.weblate.org/engage/trilium/)
|
|
||||||
|
|
||||||
[English](./README.md) | [Chinese (Simplified)](./docs/README-ZH_CN.md) | [Chinese (Traditional)](./docs/README-ZH_TW.md) | [Russian](./docs/README-ru.md) | [Japanese](./docs/README-ja.md) | [Italian](./docs/README-it.md) | [Spanish](./docs/README-es.md)
|
[](https://gitter.im/trilium-notes/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
Trilium Notes is a hierarchical note taking application with focus on building large personal knowledge bases. See [screenshots](https://github.com/zadam/trilium/wiki/Screenshot-tour) for quick overview:
|
||||||
|
|
||||||
Trilium Notes is a free and open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases.
|

|
||||||
|
|
||||||
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for quick overview:
|
## Features
|
||||||
|
|
||||||
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
|
* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://github.com/zadam/trilium/wiki/Cloning-notes))
|
||||||
|
* Rich WYSIWYG note editing including e.g. tables, images and [math](https://github.com/zadam/trilium/wiki/Text-notes#math-support) with markdown [autoformat](https://github.com/zadam/trilium/wiki/Text-notes#autoformat)
|
||||||
## ⏬ Download
|
* Support for editing [notes with source code](https://github.com/zadam/trilium/wiki/Code-notes), including syntax highlighting
|
||||||
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest) – stable version, recommended for most users.
|
* Fast and easy [navigation between notes](https://github.com/zadam/trilium/wiki/Note-navigation), full text search and [note hoisting](https://github.com/zadam/trilium/wiki/Note-hoisting)
|
||||||
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly) – unstable development version, updated daily with the latest features and fixes.
|
* Seamless [note versioning](https://github.com/zadam/trilium/wiki/Note-revisions)
|
||||||
|
* Note [attributes](https://github.com/zadam/trilium/wiki/Attributes) can be used for note organization, querying and advanced [scripting](https://github.com/zadam/trilium/wiki/Scripts)
|
||||||
## 📚 Documentation
|
* [Synchronization](https://github.com/zadam/trilium/wiki/Synchronization) with self-hosted sync server
|
||||||
|
* Strong [note encryption](https://github.com/zadam/trilium/wiki/Protected-notes) with per-note granularity
|
||||||
**Visit our comprehensive documentation at [docs.triliumnotes.org](https://docs.triliumnotes.org/)**
|
* [Relation maps](https://github.com/zadam/trilium/wiki/Relation-map) and [link maps](https://github.com/zadam/trilium/wiki/Link-map) for visualizing notes and their relations
|
||||||
|
* [Scripting](https://github.com/zadam/trilium/wiki/Scripts) - see [Advanced showcases](https://github.com/zadam/trilium/wiki/Advanced-showcases)
|
||||||
Our documentation is available in multiple formats:
|
|
||||||
- **Online Documentation**: Browse the full documentation at [docs.triliumnotes.org](https://docs.triliumnotes.org/)
|
|
||||||
- **In-App Help**: Press `F1` within Trilium to access the same documentation directly in the application
|
|
||||||
- **GitHub**: Navigate through the [User Guide](./docs/User%20Guide/User%20Guide/) in this repository
|
|
||||||
|
|
||||||
### Quick Links
|
|
||||||
- [Getting Started Guide](https://docs.triliumnotes.org/)
|
|
||||||
- [Installation Instructions](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation.md)
|
|
||||||
- [Docker Setup](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation/1.%20Installing%20the%20server/Using%20Docker.md)
|
|
||||||
- [Upgrading TriliumNext](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Upgrading%20TriliumNext.md)
|
|
||||||
- [Basic Concepts and Features](./docs/User%20Guide/User%20Guide/Basic%20Concepts%20and%20Features/Notes.md)
|
|
||||||
- [Patterns of Personal Knowledge Base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge)
|
|
||||||
|
|
||||||
## 🎁 Features
|
|
||||||
|
|
||||||
* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://triliumnext.github.io/Docs/Wiki/cloning-notes))
|
|
||||||
* Rich WYSIWYG note editor including e.g. tables, images and [math](https://triliumnext.github.io/Docs/Wiki/text-notes) with markdown [autoformat](https://triliumnext.github.io/Docs/Wiki/text-notes#autoformat)
|
|
||||||
* Support for editing [notes with source code](https://triliumnext.github.io/Docs/Wiki/code-notes), including syntax highlighting
|
|
||||||
* Fast and easy [navigation between notes](https://triliumnext.github.io/Docs/Wiki/note-navigation), full text search and [note hoisting](https://triliumnext.github.io/Docs/Wiki/note-hoisting)
|
|
||||||
* Seamless [note versioning](https://triliumnext.github.io/Docs/Wiki/note-revisions)
|
|
||||||
* Note [attributes](https://triliumnext.github.io/Docs/Wiki/attributes) can be used for note organization, querying and advanced [scripting](https://triliumnext.github.io/Docs/Wiki/scripts)
|
|
||||||
* UI available in English, German, Spanish, French, Romanian, and Chinese (simplified and traditional)
|
|
||||||
* Direct [OpenID and TOTP integration](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Server%20Installation/Multi-Factor%20Authentication.md) for more secure login
|
|
||||||
* [Synchronization](https://triliumnext.github.io/Docs/Wiki/synchronization) with self-hosted sync server
|
|
||||||
* there's a [3rd party service for hosting synchronisation server](https://trilium.cc/paid-hosting)
|
|
||||||
* [Sharing](https://triliumnext.github.io/Docs/Wiki/sharing) (publishing) notes to public internet
|
|
||||||
* Strong [note encryption](https://triliumnext.github.io/Docs/Wiki/protected-notes) with per-note granularity
|
|
||||||
* Sketching diagrams, based on [Excalidraw](https://excalidraw.com/) (note type "canvas")
|
|
||||||
* [Relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map) and [link maps](https://triliumnext.github.io/Docs/Wiki/link-map) for visualizing notes and their relations
|
|
||||||
* Mind maps, based on [Mind Elixir](https://docs.mind-elixir.com/)
|
|
||||||
* [Geo maps](./docs/User%20Guide/User%20Guide/Note%20Types/Geo%20Map.md) with location pins and GPX tracks
|
|
||||||
* [Scripting](https://triliumnext.github.io/Docs/Wiki/scripts) - see [Advanced showcases](https://triliumnext.github.io/Docs/Wiki/advanced-showcases)
|
|
||||||
* [REST API](https://triliumnext.github.io/Docs/Wiki/etapi) for automation
|
|
||||||
* Scales well in both usability and performance upwards of 100 000 notes
|
* Scales well in both usability and performance upwards of 100 000 notes
|
||||||
* Touch optimized [mobile frontend](https://triliumnext.github.io/Docs/Wiki/mobile-frontend) for smartphones and tablets
|
* Touch optimized [mobile frontend](https://github.com/zadam/trilium/wiki/Mobile-frontend) for smartphones and tablets
|
||||||
* Built-in [dark theme](https://triliumnext.github.io/Docs/Wiki/themes), support for user themes
|
* [Night theme](https://github.com/zadam/trilium/wiki/Themes)
|
||||||
* [Evernote](https://triliumnext.github.io/Docs/Wiki/evernote-import) and [Markdown import & export](https://triliumnext.github.io/Docs/Wiki/markdown)
|
* [Evernote](https://github.com/zadam/trilium/wiki/Evernote-import) and [Markdown import & export](https://github.com/zadam/trilium/wiki/Markdown)
|
||||||
* [Web Clipper](https://triliumnext.github.io/Docs/Wiki/web-clipper) for easy saving of web content
|
* [Web Clipper](https://github.com/zadam/trilium/wiki/Web-clipper) for easy saving of web content
|
||||||
* Customizable UI (sidebar buttons, user-defined widgets, ...)
|
|
||||||
* [Metrics](./docs/User%20Guide/User%20Guide/Advanced%20Usage/Metrics.md), along with a [Grafana Dashboard](./docs/User%20Guide/User%20Guide/Advanced%20Usage/Metrics/grafana-dashboard.json)
|
|
||||||
|
|
||||||
✨ Check out the following third-party resources/communities for more TriliumNext related goodies:
|
## Builds
|
||||||
|
|
||||||
- [awesome-trilium](https://github.com/Nriver/awesome-trilium) for 3rd party themes, scripts, plugins and more.
|
Trilium is provided as either desktop application (Linux and Windows) or web application hosted on your server (Linux). Mac OS desktop build is available, but it is [unsupported](https://github.com/zadam/trilium/wiki/FAQ#mac-os-support).
|
||||||
- [TriliumRocks!](https://trilium.rocks/) for tutorials, guides, and much more.
|
|
||||||
|
|
||||||
## ❓Why TriliumNext?
|
* If you want to use Trilium on the desktop, download binary release for your platform from [latest release](https://github.com/zadam/trilium/releases/latest), unzip the package and run ```trilium``` executable.
|
||||||
|
* If you want to install Trilium on server, follow [this page](https://github.com/zadam/trilium/wiki/Server-installation).
|
||||||
|
* Currently only recent Chrome and Firefox are supported (tested) browsers.
|
||||||
|
|
||||||
The original Trilium developer ([Zadam](https://github.com/zadam)) has graciously given the Trilium repository to the community project which resides at https://github.com/TriliumNext
|
## Documentation
|
||||||
|
|
||||||
### ⬆️Migrating from Zadam/Trilium?
|
[See wiki for complete list of documentation pages.](https://github.com/zadam/trilium/wiki/)
|
||||||
|
|
||||||
There are no special migration steps to migrate from a zadam/Trilium instance to a TriliumNext/Trilium instance. Simply [install TriliumNext/Trilium](#-installation) as usual and it will use your existing database.
|
You can also read [Patterns of personal knowledge base](https://github.com/zadam/trilium/wiki/Patterns-of-personal-knowledge-base) to get some inspiration on how you might use Trilium.
|
||||||
|
|
||||||
Versions up to and including [v0.90.4](https://github.com/TriliumNext/Trilium/releases/tag/v0.90.4) are compatible with the latest zadam/trilium version of [v0.63.7](https://github.com/zadam/trilium/releases/tag/v0.63.7). Any later versions of TriliumNext/Trilium have their sync versions incremented which prevents direct migration.
|
## Contribute
|
||||||
|
|
||||||
## 💬 Discuss with us
|
Use a browser based dev environment
|
||||||
|
|
||||||
Feel free to join our official conversations. We would love to hear what features, suggestions, or issues you may have!
|
[](https://gitpod.io/#https://github.com/zadam/trilium)
|
||||||
|
|
||||||
- [Matrix](https://matrix.to/#/#triliumnext:matrix.org) (For synchronous discussions.)
|
Or clone locally and run
|
||||||
- The `General` Matrix room is also bridged to [XMPP](xmpp:discuss@trilium.thisgreat.party?join)
|
```
|
||||||
- [Github Discussions](https://github.com/TriliumNext/Trilium/discussions) (For asynchronous discussions.)
|
npm install
|
||||||
- [Github Issues](https://github.com/TriliumNext/Trilium/issues) (For bug reports and feature requests.)
|
npm run start-server
|
||||||
|
|
||||||
## 🏗 Installation
|
|
||||||
|
|
||||||
### Windows / MacOS
|
|
||||||
|
|
||||||
Download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Trilium/releases/latest), unzip the package and run the `trilium` executable.
|
|
||||||
|
|
||||||
### Linux
|
|
||||||
|
|
||||||
If your distribution is listed in the table below, use your distribution's package.
|
|
||||||
|
|
||||||
[](https://repology.org/project/triliumnext/versions)
|
|
||||||
|
|
||||||
You may also download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Trilium/releases/latest), unzip the package and run the `trilium` executable.
|
|
||||||
|
|
||||||
TriliumNext is also provided as a Flatpak, but not yet published on FlatHub.
|
|
||||||
|
|
||||||
### Browser (any OS)
|
|
||||||
|
|
||||||
If you use a server installation (see below), you can directly access the web interface (which is almost identical to the desktop app).
|
|
||||||
|
|
||||||
Currently only the latest versions of Chrome & Firefox are supported (and tested).
|
|
||||||
|
|
||||||
### Mobile
|
|
||||||
|
|
||||||
To use TriliumNext on a mobile device, you can use a mobile web browser to access the mobile interface of a server installation (see below).
|
|
||||||
|
|
||||||
See issue https://github.com/TriliumNext/Trilium/issues/4962 for more information on mobile app support.
|
|
||||||
|
|
||||||
If you prefer a native Android app, you can use [TriliumDroid](https://apt.izzysoft.de/fdroid/index/apk/eu.fliegendewurst.triliumdroid).
|
|
||||||
Report bugs and missing features at [their repository](https://github.com/FliegendeWurst/TriliumDroid).
|
|
||||||
Note: It is best to disable automatic updates on your server installation (see below) when using TriliumDroid since the sync version must match between Trilium and TriliumDroid.
|
|
||||||
|
|
||||||
### Server
|
|
||||||
|
|
||||||
To install TriliumNext on your own server (including via Docker from [Dockerhub](https://hub.docker.com/r/triliumnext/trilium)) follow [the server installation docs](https://triliumnext.github.io/Docs/Wiki/server-installation).
|
|
||||||
|
|
||||||
|
|
||||||
## 💻 Contribute
|
|
||||||
|
|
||||||
### Translations
|
|
||||||
|
|
||||||
If you are a native speaker, help us translate Trilium by heading over to our [Weblate page](https://hosted.weblate.org/engage/trilium/).
|
|
||||||
|
|
||||||
Here's the language coverage we have so far:
|
|
||||||
|
|
||||||
[](https://hosted.weblate.org/engage/trilium/)
|
|
||||||
|
|
||||||
### Code
|
|
||||||
|
|
||||||
Download the repository, install dependencies using `pnpm` and then run the server (available at http://localhost:8080):
|
|
||||||
```shell
|
|
||||||
git clone https://github.com/TriliumNext/Trilium.git
|
|
||||||
cd Trilium
|
|
||||||
pnpm install
|
|
||||||
pnpm run server:start
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Documentation
|
## Shoutouts
|
||||||
|
|
||||||
Download the repository, install dependencies using `pnpm` and then run the environment required to edit the documentation:
|
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - best WYSIWYG editor on the market, very interactive and listening team
|
||||||
```shell
|
* [FancyTree](https://github.com/mar10/fancytree) - very feature rich tree library without real competition. Trilium Notes would not be the same without it.
|
||||||
git clone https://github.com/TriliumNext/Trilium.git
|
* [CodeMirror](https://github.com/codemirror/CodeMirror) - code editor with support for huge amount of languages
|
||||||
cd Trilium
|
* [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library without competition. Used in [relation maps](https://github.com/zadam/trilium/wiki/Relation-map) and [link maps](https://github.com/zadam/trilium/wiki/Link-map)
|
||||||
pnpm install
|
|
||||||
pnpm edit-docs:edit-docs
|
|
||||||
```
|
|
||||||
|
|
||||||
### Building the Executable
|
## License
|
||||||
Download the repository, install dependencies using `pnpm` and then build the desktop app for Windows:
|
|
||||||
```shell
|
|
||||||
git clone https://github.com/TriliumNext/Trilium.git
|
|
||||||
cd Trilium
|
|
||||||
pnpm install
|
|
||||||
pnpm run --filter desktop electron-forge:make --arch=x64 --platform=win32
|
|
||||||
```
|
|
||||||
|
|
||||||
For more details, see the [development docs](https://github.com/TriliumNext/Trilium/tree/main/docs/Developer%20Guide/Developer%20Guide).
|
|
||||||
|
|
||||||
### Developer Documentation
|
|
||||||
|
|
||||||
Please view the [documentation guide](https://github.com/TriliumNext/Trilium/blob/main/docs/Developer%20Guide/Developer%20Guide/Environment%20Setup.md) for details. If you have more questions, feel free to reach out via the links described in the "Discuss with us" section above.
|
|
||||||
|
|
||||||
## 👏 Shoutouts
|
|
||||||
|
|
||||||
* [zadam](https://github.com/zadam) for the original concept and implementation of the application.
|
|
||||||
* [Sarah Hussein](https://github.com/Sarah-Hussein) for designing the application icon.
|
|
||||||
* [nriver](https://github.com/nriver) for his work on internationalization.
|
|
||||||
* [Thomas Frei](https://github.com/thfrei) for his original work on the Canvas.
|
|
||||||
* [antoniotejada](https://github.com/nriver) for the original syntax highlight widget.
|
|
||||||
* [Dosu](https://dosu.dev/) for providing us with the automated responses to GitHub issues and discussions.
|
|
||||||
* [Tabler Icons](https://tabler.io/icons) for the system tray icons.
|
|
||||||
|
|
||||||
Trilium would not be possible without the technologies behind it:
|
|
||||||
|
|
||||||
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - the visual editor behind text notes. We are grateful for being offered a set of the premium features.
|
|
||||||
* [CodeMirror](https://github.com/codemirror/CodeMirror) - code editor with support for huge amount of languages.
|
|
||||||
* [Excalidraw](https://github.com/excalidraw/excalidraw) - the infinite whiteboard used in Canvas notes.
|
|
||||||
* [Mind Elixir](https://github.com/SSShooter/mind-elixir-core) - providing the mind map functionality.
|
|
||||||
* [Leaflet](https://github.com/Leaflet/Leaflet) - for rendering geographical maps.
|
|
||||||
* [Tabulator](https://github.com/olifolkerd/tabulator) - for the interactive table used in collections.
|
|
||||||
* [FancyTree](https://github.com/mar10/fancytree) - feature-rich tree library without real competition.
|
|
||||||
* [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library. Used in [relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map.html) and [link maps](https://triliumnext.github.io/Docs/Wiki/note-map.html#link-map)
|
|
||||||
|
|
||||||
## 🤝 Support
|
|
||||||
|
|
||||||
Trilium is built and maintained with [hundreds of hours of work](https://github.com/TriliumNext/Trilium/graphs/commit-activity). Your support keeps it open-source, improves features, and covers costs such as hosting.
|
|
||||||
|
|
||||||
Consider supporting the main developer ([eliandoran](https://github.com/eliandoran)) of the application via:
|
|
||||||
|
|
||||||
- [GitHub Sponsors](https://github.com/sponsors/eliandoran)
|
|
||||||
- [PayPal](https://paypal.me/eliandoran)
|
|
||||||
- [Buy Me a Coffee](https://buymeacoffee.com/eliandoran)
|
|
||||||
|
|
||||||
|
|
||||||
## 🔑 License
|
|
||||||
|
|
||||||
Copyright 2017-2025 zadam, Elian Doran, and other contributors
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
|||||||
63
README.ru.md
Normal file
63
README.ru.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Trilium Notes
|
||||||
|
|
||||||
|
[English](https://github.com/zadam/trilium/blob/master/README.md) | [Chinese](https://github.com/zadam/trilium/blob/master/README-ZH_CN.md) | [Russian](https://github.com/zadam/trilium/blob/master/README.ru.md)
|
||||||
|
|
||||||
|
[](https://gitter.im/trilium-notes/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
Trilium Notes – это приложение для заметок с иерархической структурой, ориентированное на создание больших персональных баз знаний. Для быстрого ознакомления посмотрите [скриншот-тур](https://github.com/zadam/trilium/wiki/Screenshot-tour):
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Возможности
|
||||||
|
|
||||||
|
* Заметки можно расположить в виде дерева произвольной глубины. Отдельную заметку можно разместить в нескольких местах дерева (см. [клонирование](https://github.com/zadam/trilium/wiki/Cloning-notes))
|
||||||
|
* Продвинутый визуальный редактор (WYSIWYG) позволяет работать с таблицами, изображениями, [формулами](https://github.com/zadam/trilium/wiki/Text-notes#math-support) и разметкой markdown, имеет [автоформатирование](https://github.com/zadam/trilium/wiki/Text-notes#autoformat)
|
||||||
|
* Редактирование [заметок с исходным кодом](https://github.com/zadam/trilium/wiki/Code-notes), включая подсветку синтаксиса
|
||||||
|
* Быстрая и простая [навигация между заметками](https://github.com/zadam/trilium/wiki/Note-navigation), полнотекстовый поиск и [выделение заметок](https://github.com/zadam/trilium/wiki/Note-hoisting) в отдельный блок
|
||||||
|
* Бесшовное [версионирование заметки](https://github.com/zadam/trilium/wiki/Note-revisions)
|
||||||
|
* Специальные [атрибуты](https://github.com/zadam/trilium/wiki/Attributes) позволяют гибко организовать структуру, используются для поиска и продвинутого [скриптинга](https://github.com/zadam/trilium/wiki/Scripts)
|
||||||
|
* [Синхронизация](https://github.com/zadam/trilium/wiki/Synchronization) заметок со своим сервером
|
||||||
|
* Надёжное [шифрование](https://github.com/zadam/trilium/wiki/Protected-notes) с детализацией по каждой заметке
|
||||||
|
* [Карты связей](https://github.com/zadam/trilium/wiki/Relation-map) и [карты ссылок](https://github.com/zadam/trilium/wiki/Link-map) для визуализации их взяимосвязей
|
||||||
|
* [Скрипты](https://github.com/zadam/trilium/wiki/Scripts) - см. [продвинутые примеры](https://github.com/zadam/trilium/wiki/Advanced-showcases)
|
||||||
|
* Хорошо масштабируется, как по удобству использования, так и по производительности до 100000 заметок
|
||||||
|
* Оптимизированный [мобильный фронтенд](https://github.com/zadam/trilium/wiki/Mobile-frontend) смартфонов и планшетов
|
||||||
|
* [Темная тема](https://github.com/zadam/trilium/wiki/Themes)
|
||||||
|
* Импорт и экпорт [Evernote](https://github.com/zadam/trilium/wiki/Evernote-import) и данных в [markdown](https://github.com/zadam/trilium/wiki/Markdown) формате
|
||||||
|
* [Web Clipper](https://github.com/zadam/trilium/wiki/Web-clipper) для удобного сохранения веб-контента
|
||||||
|
|
||||||
|
## Сборки
|
||||||
|
|
||||||
|
Trilium предоставляется в виде десктопного приложения (Linux и Windows) или веб-приложения, размещенного на вашем сервере (Linux). Доступна сборка Mac OS, но она [не поддерживается](https://github.com/zadam/trilium/wiki/FAQ#mac-os-support).
|
||||||
|
|
||||||
|
* Если вы хотите использовать Trilium на десктопе, скачайте архив для своей платформы со страницы [релизов](https://github.com/zadam/trilium/releases/latest), распакуйте и запустите исполняемый файл ```trilium```.
|
||||||
|
* Если вы хотите установить Trilium на сервере, следуйте этой [инструкции](https://github.com/zadam/trilium/wiki/Server-installation).
|
||||||
|
* В данный момент поддерживаются (протестированы) последние версии браузеров Chrome и Firefox.
|
||||||
|
|
||||||
|
## Документация
|
||||||
|
|
||||||
|
[Полный список страниц документации доступен в Wiki.](https://github.com/zadam/trilium/wiki/)
|
||||||
|
|
||||||
|
Вы также можете ознакомиться с [шаблонами персональных баз знаний](https://github.com/zadam/trilium/wiki/Patterns-of-personal-knowledge-base), чтобы получить представление о том, как можно использовать Trilium.
|
||||||
|
|
||||||
|
## Участвуйте в разработке
|
||||||
|
|
||||||
|
Используйте онлайн среду разработки в браузере
|
||||||
|
|
||||||
|
[](https://gitpod.io/#https://github.com/zadam/trilium)
|
||||||
|
|
||||||
|
Или склонируйте на своё устройство и запустите
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
npm run start-server
|
||||||
|
```
|
||||||
|
|
||||||
|
## Благодарности
|
||||||
|
|
||||||
|
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - лучший WYSIWYG редактор, очень активная и внимательная команда.
|
||||||
|
* [FancyTree](https://github.com/mar10/fancytree) - многофункциональная библиотека для создания древовидных структур. Вне конкуренции. Без него Trilium Notes не были бы таким.
|
||||||
|
* [CodeMirror](https://github.com/codemirror/CodeMirror) - редактор кода с поддержкой огромного количество языков.
|
||||||
|
* [jsPlumb](https://github.com/jsplumb/jsplumb) - библиотека для визуализации связей. Вне конкуренции. Используется в [картах связей](https://github.com/zadam/trilium/wiki/Relation-map) и [картах ссылок](https://github.com/zadam/trilium/wiki/Link-map).
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
Эта программа является бесплатным программным обеспечением: вы можете распространять и/или изменять ее в соответствии с условиями GNU Affero General Public License, опубликованной Free Software Foundation, либо версии 3 Лицензии, либо (по вашему выбору) любой более поздней версии.
|
||||||
@@ -10,4 +10,4 @@ Description above is a general rule and may be altered on case by case basis.
|
|||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
You can report low severity vulnerabilities as GitHub issues, more severe vulnerabilities should be reported to the email [contact@eliandoran.me](mailto:contact@eliandoran.me)
|
You can report low severity vulnerabilities as GitHub issues, more severe vulnerabilities should be reported to the email zadam.apps@gmail.com
|
||||||
|
|||||||
3
TODO
Normal file
3
TODO
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
- new icon
|
||||||
|
- polish becca entities API
|
||||||
|
- separate private and public APIs in becca entities
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
import anonymizationService from "../src/services/anonymization.js";
|
|
||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
fs.writeFileSync(path.resolve(__dirname, "tpl", "anonymize-database.sql"), anonymizationService.getFullAnonymizationScript());
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
if ! command -v magick &> /dev/null; then
|
|
||||||
echo "This tool requires ImageMagick to be installed in order to create the icons."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v inkscape &> /dev/null; then
|
|
||||||
echo "This tool requires Inkscape to be render sharper SVGs than ImageMagick."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v icnsutil &> /dev/null; then
|
|
||||||
echo "This tool requires icnsutil to be installed in order to generate macOS icons."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
script_dir=$(realpath $(dirname $0))
|
|
||||||
cd "${script_dir}/../images/app-icons"
|
|
||||||
inkscape -w 180 -h 180 "../icon-color.svg" -o "./ios/apple-touch-icon.png"
|
|
||||||
|
|
||||||
# Build PNGs
|
|
||||||
inkscape -w 128 -h 128 "../icon-color.svg" -o "./png/128x128.png"
|
|
||||||
inkscape -w 256 -h 256 "../icon-color.svg" -o "./png/256x256.png"
|
|
||||||
|
|
||||||
# Build dev icons (including tray)
|
|
||||||
inkscape -w 16 -h 16 "../icon-purple.svg" -o "./png/16x16-dev.png"
|
|
||||||
inkscape -w 32 -h 32 "../icon-purple.svg" -o "./png/32x32-dev.png"
|
|
||||||
inkscape -w 256 -h 256 "../icon-purple.svg" -o "./png/256x256-dev.png"
|
|
||||||
|
|
||||||
# Build Mac .icns
|
|
||||||
declare -a sizes=("16" "32" "512" "1024")
|
|
||||||
for size in "${sizes[@]}"; do
|
|
||||||
inkscape -w $size -h $size "../icon-color.svg" -o "./png/${size}x${size}.png"
|
|
||||||
done
|
|
||||||
|
|
||||||
mkdir -p fakeapp.app
|
|
||||||
npx iconsur set fakeapp.app -l -i "png/1024x1024.png" -o "mac/1024x1024.png" -s 0.8
|
|
||||||
declare -a sizes=("16x16" "32x32" "128x128" "512x512")
|
|
||||||
for size in "${sizes[@]}"; do
|
|
||||||
magick "mac/1024x1024.png" -resize "${size}" "mac/${size}.png"
|
|
||||||
done
|
|
||||||
icnsutil compose -f "mac/icon.icns" ./mac/*.png
|
|
||||||
|
|
||||||
# Build Windows icon
|
|
||||||
magick -background none "../icon-color.svg" -define icon:auto-resize=16,32,48,64,128,256 "./icon.ico"
|
|
||||||
|
|
||||||
# Build Windows setup icon
|
|
||||||
magick -background none "../icon-installer.svg" -define icon:auto-resize=16,32,48,64,128,256 "./win/setup.ico"
|
|
||||||
|
|
||||||
# Build Squirrel splash image
|
|
||||||
magick "./png/256x256.png" -background "#ffffff" -gravity center -extent 640x480 "./win/setup-banner.gif"
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
SCHEMA_FILE_PATH=db/schema.sql
|
|
||||||
|
|
||||||
sqlite3 ./data/document.db .schema | grep -v "sqlite_sequence" > "$SCHEMA_FILE_PATH"
|
|
||||||
|
|
||||||
echo "DB schema exported to $SCHEMA_FILE_PATH"
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
/**
|
|
||||||
* Usage: tsx ./generate_document.ts 1000
|
|
||||||
* will create 1000 new notes and some clones into the current document.db
|
|
||||||
*/
|
|
||||||
|
|
||||||
import sqlInit from "../src/services/sql_init.js";
|
|
||||||
import noteService from "../src/services/notes.js";
|
|
||||||
import attributeService from "../src/services/attributes.js";
|
|
||||||
import cls from "../src/services/cls.js";
|
|
||||||
import cloningService from "../src/services/cloning.js";
|
|
||||||
import loremIpsum from "lorem-ipsum";
|
|
||||||
import "../src/becca/entity_constructor.js";
|
|
||||||
|
|
||||||
const noteCount = parseInt(process.argv[2]);
|
|
||||||
|
|
||||||
if (!noteCount) {
|
|
||||||
console.error(`Please enter number of notes as program parameter.`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const notes = ["root"];
|
|
||||||
|
|
||||||
function getRandomNoteId() {
|
|
||||||
const index = Math.floor(Math.random() * notes.length);
|
|
||||||
|
|
||||||
return notes[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
async function start() {
|
|
||||||
for (let i = 0; i < noteCount; i++) {
|
|
||||||
const title = loremIpsum.loremIpsum({
|
|
||||||
count: 1,
|
|
||||||
units: "sentences",
|
|
||||||
sentenceLowerBound: 1,
|
|
||||||
sentenceUpperBound: 10
|
|
||||||
});
|
|
||||||
|
|
||||||
const paragraphCount = Math.floor(Math.random() * Math.random() * 100);
|
|
||||||
const content = loremIpsum.loremIpsum({
|
|
||||||
count: paragraphCount,
|
|
||||||
units: "paragraphs",
|
|
||||||
sentenceLowerBound: 1,
|
|
||||||
sentenceUpperBound: 15,
|
|
||||||
paragraphLowerBound: 3,
|
|
||||||
paragraphUpperBound: 10,
|
|
||||||
format: "html"
|
|
||||||
});
|
|
||||||
|
|
||||||
const { note } = noteService.createNewNote({
|
|
||||||
parentNoteId: getRandomNoteId(),
|
|
||||||
title,
|
|
||||||
content,
|
|
||||||
type: "text"
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`Created note ${i}: ${title}`);
|
|
||||||
|
|
||||||
if (Math.random() < 0.04) {
|
|
||||||
const noteIdToClone = note.noteId;
|
|
||||||
const parentNoteId = getRandomNoteId();
|
|
||||||
const prefix = Math.random() > 0.8 ? "prefix" : "";
|
|
||||||
|
|
||||||
const result = await cloningService.cloneNoteToBranch(noteIdToClone, parentNoteId, prefix);
|
|
||||||
|
|
||||||
console.log(`Cloning ${i}:`, result.success ? "succeeded" : "FAILED");
|
|
||||||
}
|
|
||||||
|
|
||||||
// does not have to be for the current note
|
|
||||||
await attributeService.createAttribute({
|
|
||||||
noteId: getRandomNoteId(),
|
|
||||||
type: "label",
|
|
||||||
name: "label",
|
|
||||||
value: "value",
|
|
||||||
isInheritable: Math.random() > 0.1 // 10% are inheritable
|
|
||||||
});
|
|
||||||
|
|
||||||
await attributeService.createAttribute({
|
|
||||||
noteId: getRandomNoteId(),
|
|
||||||
type: "relation",
|
|
||||||
name: "relation",
|
|
||||||
value: getRandomNoteId(),
|
|
||||||
isInheritable: Math.random() > 0.1 // 10% are inheritable
|
|
||||||
});
|
|
||||||
|
|
||||||
note.saveRevision();
|
|
||||||
|
|
||||||
notes.push(note.noteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @TriliumNextTODO sqlInit.dbReady never seems to resolve so program hangs
|
|
||||||
// see https://github.com/TriliumNext/Trilium/issues/1020
|
|
||||||
sqlInit.dbReady.then(cls.wrap(start)).catch((err) => console.error(err));
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
if [[ $# -eq 0 ]] ; then
|
|
||||||
echo "Missing argument of new version"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
VERSION=$1
|
|
||||||
|
|
||||||
if ! [[ ${VERSION} =~ ^[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}(-.+)?$ ]] ;
|
|
||||||
then
|
|
||||||
echo "Version ${VERSION} isn't in format X.Y.Z"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
VERSION_DATE=$(git log -1 --format=%aI "v${VERSION}" | cut -c -10)
|
|
||||||
VERSION_COMMIT=$(git rev-list -n 1 "v${VERSION}")
|
|
||||||
|
|
||||||
# expecting the directory at a specific path
|
|
||||||
cd ~/trilium-flathub || exit
|
|
||||||
|
|
||||||
if ! git diff-index --quiet HEAD --; then
|
|
||||||
echo "There are uncommitted changes"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
BASE_BRANCH=main
|
|
||||||
|
|
||||||
if [[ "$VERSION" == *"beta"* ]]; then
|
|
||||||
BASE_BRANCH=beta
|
|
||||||
fi
|
|
||||||
|
|
||||||
git switch "${BASE_BRANCH}"
|
|
||||||
git pull
|
|
||||||
|
|
||||||
BRANCH=b${VERSION}
|
|
||||||
|
|
||||||
git branch "${BRANCH}"
|
|
||||||
git switch "${BRANCH}"
|
|
||||||
|
|
||||||
echo "Updating files with version ${VERSION}, date ${VERSION_DATE} and commit ${VERSION_COMMIT}"
|
|
||||||
|
|
||||||
flatpak-node-generator npm ../trilium/package-lock.json
|
|
||||||
|
|
||||||
xmlstarlet ed --inplace --update "/component/releases/release/@version" --value "${VERSION}" --update "/component/releases/release/@date" --value "${VERSION_DATE}" ./com.github.zadam.trilium.metainfo.xml
|
|
||||||
|
|
||||||
yq --inplace "(.modules[0].sources[0].tag = \"v${VERSION}\") | (.modules[0].sources[0].commit = \"${VERSION_COMMIT}\")" ./com.github.zadam.trilium.yml
|
|
||||||
|
|
||||||
git add ./generated-sources.json
|
|
||||||
git add ./com.github.zadam.trilium.metainfo.xml
|
|
||||||
git add ./com.github.zadam.trilium.yml
|
|
||||||
|
|
||||||
git commit -m "release $VERSION"
|
|
||||||
git push --set-upstream origin "${BRANCH}"
|
|
||||||
|
|
||||||
gh pr create --fill -B "${BASE_BRANCH}"
|
|
||||||
gh pr merge --auto --merge --delete-branch
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [[ $# -eq 0 ]] ; then
|
|
||||||
echo "Missing argument of new version"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v jq &> /dev/null; then
|
|
||||||
echo "Missing command: jq"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
VERSION=$1
|
|
||||||
|
|
||||||
if ! [[ ${VERSION} =~ ^[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}(-.+)?$ ]] ;
|
|
||||||
then
|
|
||||||
echo "Version ${VERSION} isn't in format X.Y.Z"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! git diff-index --quiet HEAD --; then
|
|
||||||
echo "There are uncommitted changes"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Releasing Trilium $VERSION"
|
|
||||||
|
|
||||||
jq '.version = "'$VERSION'"' package.json > package.json.tmp
|
|
||||||
mv package.json.tmp package.json
|
|
||||||
|
|
||||||
git add package.json
|
|
||||||
|
|
||||||
npm run chore:update-build-info
|
|
||||||
|
|
||||||
git add src/services/build.ts
|
|
||||||
|
|
||||||
TAG=v$VERSION
|
|
||||||
|
|
||||||
echo "Committing package.json version change"
|
|
||||||
|
|
||||||
git commit -m "chore(release): $VERSION"
|
|
||||||
git push
|
|
||||||
|
|
||||||
echo "Tagging commit with $TAG"
|
|
||||||
|
|
||||||
git tag $TAG
|
|
||||||
git push origin $TAG
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Create PO files to make easier the labor of translation.
|
|
||||||
#
|
|
||||||
# Info:
|
|
||||||
# https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
|
|
||||||
# https://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/json2po.html
|
|
||||||
#
|
|
||||||
# Dependencies:
|
|
||||||
# jq
|
|
||||||
# translate-toolkit
|
|
||||||
# python-wcwidth
|
|
||||||
#
|
|
||||||
# Created by @hasecilu
|
|
||||||
#
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
number_of_keys() {
|
|
||||||
[ -f "$1" ] && jq 'path(..) | select(length == 2) | .[1]' "$1" | wc -l || echo "0"
|
|
||||||
}
|
|
||||||
|
|
||||||
stats() {
|
|
||||||
# Print the number of existing strings on the JSON files for each locale
|
|
||||||
s=$(number_of_keys "${paths[0]}/en/server.json")
|
|
||||||
c=$(number_of_keys "${paths[1]}/en/translation.json")
|
|
||||||
echo "| locale | server strings | client strings |"
|
|
||||||
echo "|--------|----------------|----------------|"
|
|
||||||
echo "| en | ${s} | ${c} |"
|
|
||||||
echo "|--------|----------------|----------------|"
|
|
||||||
for locale in "${locales[@]}"; do
|
|
||||||
s=$(number_of_keys "${paths[0]}/${locale}/server.json")
|
|
||||||
c=$(number_of_keys "${paths[1]}/${locale}/translation.json")
|
|
||||||
n1=$(((8 - ${#locale}) / 2))
|
|
||||||
n2=$((n1 == 1 ? n1 + 1 : n1))
|
|
||||||
echo "|$(printf "%${n1}s")${locale}$(printf "%${n2}s")| ${s} | ${c} |"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
update_1() {
|
|
||||||
# Update PO files from English and localized JSON files as source
|
|
||||||
# NOTE: if you want a new language you need to first create the JSON files
|
|
||||||
# on their corresponding place with `{}` as content to avoid error on `json2po`
|
|
||||||
local locales=("$@")
|
|
||||||
for path in "${paths[@]}"; do
|
|
||||||
for locale in "${locales[@]}"; do
|
|
||||||
json2po -t "${path}/en" "${path}/${locale}" "${path}/po-${locale}"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
update_2() {
|
|
||||||
# Recover translation from PO files to localized JSON files
|
|
||||||
local locales=("$@")
|
|
||||||
for path in "${paths[@]}"; do
|
|
||||||
for locale in "${locales[@]}"; do
|
|
||||||
po2json -t "${path}/en" "${path}/po-${locale}" "${path}/${locale}"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
help() {
|
|
||||||
echo -e "\nDescription:"
|
|
||||||
echo -e "\tCreate PO files to make easier the labor of translation"
|
|
||||||
echo -e "\nUsage:"
|
|
||||||
echo -e "\t./translation.sh [--stats] [--update1 <OPT_LOCALE>] [--update2 <OPT_LOCALE>]"
|
|
||||||
echo -e "\nFlags:"
|
|
||||||
echo -e " --clear\n\tClear all po-* directories"
|
|
||||||
echo -e " --stats\n\tPrint the number of existing strings on the JSON files for each locale"
|
|
||||||
echo -e " --update1 <LOCALE>\n\tUpdate PO files from English and localized JSON files as source"
|
|
||||||
echo -e " --update2 <LOCALE>\n\tRecover translation from PO files to localized JSON files"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main function ------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# Get script directory to set file path relative to it
|
|
||||||
file_path="$(
|
|
||||||
cd -- "$(dirname "${0}")" >/dev/null 2>&1 || exit
|
|
||||||
pwd -P
|
|
||||||
)"
|
|
||||||
paths=(
|
|
||||||
"${file_path}/../../apps/server/src/assets/translations/"
|
|
||||||
"${file_path}/../../apps/client/src/translations/"
|
|
||||||
)
|
|
||||||
locales=(cn de es fr pt_br ro tw)
|
|
||||||
|
|
||||||
if [ $# -eq 1 ]; then
|
|
||||||
if [ "$1" == "--clear" ]; then
|
|
||||||
for path in "${paths[@]}"; do
|
|
||||||
for locale in "${locales[@]}"; do
|
|
||||||
[ -d "${path}/po-${locale}" ] && rm -r "${path}/po-${locale}"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
elif [ "$1" == "--stats" ]; then
|
|
||||||
stats
|
|
||||||
elif [ "$1" == "--update1" ]; then
|
|
||||||
update_1 "${locales[@]}"
|
|
||||||
elif [ "$1" == "--update2" ]; then
|
|
||||||
update_2 "${locales[@]}"
|
|
||||||
else
|
|
||||||
help
|
|
||||||
fi
|
|
||||||
elif [ $# -eq 2 ]; then
|
|
||||||
if [ "$1" == "--update1" ]; then
|
|
||||||
update_1 "$2"
|
|
||||||
elif [ "$1" == "--update2" ]; then
|
|
||||||
update_2 "$2"
|
|
||||||
else
|
|
||||||
help
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
help
|
|
||||||
fi
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-bookmark"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M18 7v14l-6 -4l-6 4v-14a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4z" /></svg>
|
|
||||||
|
Before Width: | Height: | Size: 383 B |
@@ -1,39 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
if ! command -v magick &> /dev/null; then
|
|
||||||
echo "This tool requires ImageMagick to be installed in order to create the icons."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v inkscape &> /dev/null; then
|
|
||||||
echo "This tool requires Inkscape to be render sharper SVGs than ImageMagick."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
script_dir=$(realpath $(dirname $0))
|
|
||||||
images_dir="$script_dir/../../images"
|
|
||||||
output_dir="$images_dir/app-icons/tray"
|
|
||||||
|
|
||||||
function generateDpiScaledIcons {
|
|
||||||
file=$1
|
|
||||||
suffix=$2
|
|
||||||
name="$(basename $file .svg)$suffix"
|
|
||||||
inkscape -w 16 -h 16 "$file" -o "$output_dir/$name.png"
|
|
||||||
inkscape -w 20 -h 20 "$file" -o "$output_dir/$name@1.25x.png"
|
|
||||||
inkscape -w 24 -h 24 "$file" -o "$output_dir/$name@1.5x.png"
|
|
||||||
inkscape -w 32 -h 32 "$file" -o "$output_dir/$name@2x.png"
|
|
||||||
}
|
|
||||||
|
|
||||||
generateDpiScaledIcons "$images_dir/icon-black.svg" "Template"
|
|
||||||
generateDpiScaledIcons "$images_dir/icon-color.svg"
|
|
||||||
generateDpiScaledIcons "$images_dir/icon-purple.svg"
|
|
||||||
|
|
||||||
for file in *.svg; do
|
|
||||||
name="$(basename $file .svg)Template"
|
|
||||||
generateDpiScaledIcons "$file" "Template"
|
|
||||||
magick "$output_dir/$name.png" -channel RGB -negate "$output_dir/$name-inverted.png"
|
|
||||||
magick "$output_dir/$name@1.25x.png" -channel RGB -negate "$output_dir/$name-inverted@1.25x.png"
|
|
||||||
magick "$output_dir/$name@1.5x.png" -channel RGB -negate "$output_dir/$name-inverted@1.5x.png"
|
|
||||||
magick "$output_dir/$name@2x.png" -channel RGB -negate "$output_dir/$name-inverted@2x.png"
|
|
||||||
done
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-x"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M18 6l-12 12" /><path d="M6 6l12 12" /></svg>
|
|
||||||
|
Before Width: | Height: | Size: 356 B |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-plus"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 5l0 14" /><path d="M5 12l14 0" /></svg>
|
|
||||||
|
Before Width: | Height: | Size: 357 B |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-history"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 8l0 4l2 2" /><path d="M3.05 11a9 9 0 1 1 .5 4m-.5 5v-5h5" /></svg>
|
|
||||||
|
Before Width: | Height: | Size: 387 B |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-calendar-star"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M11 21h-5a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v3.5" /><path d="M16 3v4" /><path d="M8 3v4" /><path d="M4 11h11" /><path d="M17.8 20.817l-2.172 1.138a.392 .392 0 0 1 -.568 -.41l.415 -2.411l-1.757 -1.707a.389 .389 0 0 1 .217 -.665l2.428 -.352l1.086 -2.193a.392 .392 0 0 1 .702 0l1.086 2.193l2.428 .352a.39 .39 0 0 1 .217 .665l-1.757 1.707l.414 2.41a.39 .39 0 0 1 -.567 .411l-2.172 -1.138z" /></svg>
|
|
||||||
|
Before Width: | Height: | Size: 734 B |
@@ -1,10 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import eslint from "@eslint/js";
|
|
||||||
import tseslint from "typescript-eslint";
|
|
||||||
import simpleImportSort from "eslint-plugin-simple-import-sort";
|
|
||||||
|
|
||||||
export default tseslint.config(
|
|
||||||
eslint.configs.recommended,
|
|
||||||
tseslint.configs.recommended,
|
|
||||||
// consider using rules below, once we have a full TS codebase and can be more strict
|
|
||||||
// tseslint.configs.strictTypeChecked,
|
|
||||||
// tseslint.configs.stylisticTypeChecked,
|
|
||||||
// tseslint.configs.recommendedTypeChecked,
|
|
||||||
{
|
|
||||||
languageOptions: {
|
|
||||||
parserOptions: {
|
|
||||||
projectService: true,
|
|
||||||
tsconfigRootDir: import.meta.dirname
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugins: {
|
|
||||||
"simple-import-sort": simpleImportSort
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rules: {
|
|
||||||
// add rule overrides here
|
|
||||||
"no-undef": "off",
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
argsIgnorePattern: "^_",
|
|
||||||
varsIgnorePattern: "^_"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"simple-import-sort/imports": "error",
|
|
||||||
"simple-import-sort/exports": "error"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ignores: [
|
|
||||||
"build/*",
|
|
||||||
"dist/*",
|
|
||||||
"docs/*",
|
|
||||||
"demo/*",
|
|
||||||
"src/public/app-dist/*",
|
|
||||||
"src/public/app/doc_notes/*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
);
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import stylistic from "@stylistic/eslint-plugin";
|
|
||||||
import tsParser from "@typescript-eslint/parser";
|
|
||||||
|
|
||||||
// eslint config just for formatting rules
|
|
||||||
// potentially to be merged with the linting rules into one single config,
|
|
||||||
// once we have fixed the majority of lint errors
|
|
||||||
|
|
||||||
// Go to https://eslint.style/rules/default/${rule_without_prefix} to check the rule details
|
|
||||||
export const stylisticRules = {
|
|
||||||
"@stylistic/indent": [ "error", 4 ],
|
|
||||||
"@stylistic/quotes": [ "error", "double", { avoidEscape: true, allowTemplateLiterals: "always" } ],
|
|
||||||
"@stylistic/semi": [ "error", "always" ],
|
|
||||||
"@stylistic/quote-props": [ "error", "consistent-as-needed" ],
|
|
||||||
"@stylistic/max-len": [ "error", { code: 100 } ],
|
|
||||||
"@stylistic/comma-dangle": [ "error", "never" ],
|
|
||||||
"@stylistic/linebreak-style": [ "error", "unix" ],
|
|
||||||
"@stylistic/array-bracket-spacing": [ "error", "always" ],
|
|
||||||
"@stylistic/object-curly-spacing": [ "error", "always" ],
|
|
||||||
"@stylistic/padded-blocks": [ "error", { classes: "always" } ]
|
|
||||||
};
|
|
||||||
|
|
||||||
export default [
|
|
||||||
{
|
|
||||||
files: [ "**/*.{js,ts,mjs,cjs}" ],
|
|
||||||
languageOptions: {
|
|
||||||
parser: tsParser
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
"@stylistic": stylistic
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
...stylisticRules
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ignores: [
|
|
||||||
"build/*",
|
|
||||||
"dist/*",
|
|
||||||
"docs/*",
|
|
||||||
"demo/*",
|
|
||||||
// TriliumNextTODO: check if we want to format packages here as well - for now skipping it
|
|
||||||
"packages/*",
|
|
||||||
"src/public/app-dist/*",
|
|
||||||
"src/public/app/doc_notes/*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import { test as setup, expect } from "@playwright/test";
|
|
||||||
|
|
||||||
const authFile = "playwright/.auth/user.json";
|
|
||||||
|
|
||||||
const ROOT_URL = "http://localhost:8082";
|
|
||||||
const LOGIN_PASSWORD = "demo1234";
|
|
||||||
|
|
||||||
// Reference: https://playwright.dev/docs/auth#basic-shared-account-in-all-tests
|
|
||||||
|
|
||||||
setup("authenticate", async ({ page }) => {
|
|
||||||
await page.goto(ROOT_URL);
|
|
||||||
await expect(page).toHaveURL(`${ROOT_URL}/login`);
|
|
||||||
|
|
||||||
await page.getByRole("textbox", { name: "Password" }).fill(LOGIN_PASSWORD);
|
|
||||||
await page.getByRole("button", { name: "Login" }).click();
|
|
||||||
await page.context().storageState({ path: authFile });
|
|
||||||
});
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { test, expect } from "@playwright/test";
|
|
||||||
|
|
||||||
test("Can duplicate note with broken links", async ({ page }) => {
|
|
||||||
await page.goto(`http://localhost:8082/#2VammGGdG6Ie`);
|
|
||||||
await page.locator(".tree-wrapper .fancytree-active").getByText("Note map").click({ button: "right" });
|
|
||||||
await page.getByText("Duplicate subtree").click();
|
|
||||||
await expect(page.locator(".toast-body")).toBeHidden();
|
|
||||||
await expect(page.locator(".tree-wrapper").getByText("Note map (dup)")).toBeVisible();
|
|
||||||
});
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { test, expect } from "@playwright/test";
|
|
||||||
|
|
||||||
test("has title", async ({ page }) => {
|
|
||||||
await page.goto("https://playwright.dev/");
|
|
||||||
|
|
||||||
// Expect a title "to contain" a substring.
|
|
||||||
await expect(page).toHaveTitle(/Playwright/);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("get started link", async ({ page }) => {
|
|
||||||
await page.goto("https://playwright.dev/");
|
|
||||||
|
|
||||||
// Click the get started link.
|
|
||||||
await page.getByRole("link", { name: "Get started" }).click();
|
|
||||||
|
|
||||||
// Expects page to have a heading with the name of Installation.
|
|
||||||
await expect(page.getByRole("heading", { name: "Installation" })).toBeVisible();
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import test, { expect } from "@playwright/test";
|
|
||||||
|
|
||||||
test("Native Title Bar not displayed on web", async ({ page }) => {
|
|
||||||
await page.goto("http://localhost:8082/#root/_hidden/_options/_optionsAppearance");
|
|
||||||
await expect(page.getByRole("heading", { name: "Theme" })).toBeVisible();
|
|
||||||
await expect(page.getByRole("heading", { name: "Native Title Bar (requires" })).toBeHidden();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Tray settings not displayed on web", async ({ page }) => {
|
|
||||||
await page.goto("http://localhost:8082/#root/_hidden/_options/_optionsOther");
|
|
||||||
await expect(page.getByRole("heading", { name: "Note Erasure Timeout" })).toBeVisible();
|
|
||||||
await expect(page.getByRole("heading", { name: "Tray" })).toBeHidden();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Spellcheck settings not displayed on web", async ({ page }) => {
|
|
||||||
await page.goto("http://localhost:8082/#root/_hidden/_options/_optionsSpellcheck");
|
|
||||||
await expect(page.getByRole("heading", { name: "Spell Check" })).toBeVisible();
|
|
||||||
await expect(page.getByRole("heading", { name: "Tray" })).toBeHidden();
|
|
||||||
await expect(page.getByText("These options apply only for desktop builds")).toBeVisible();
|
|
||||||
await expect(page.getByText("Enable spellcheck")).toBeHidden();
|
|
||||||
});
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import test, { expect } from "@playwright/test";
|
|
||||||
|
|
||||||
test("Renders on desktop", async ({ page, context }) => {
|
|
||||||
await page.goto("http://localhost:8082");
|
|
||||||
await expect(page.locator(".tree")).toContainText("Trilium Integration Test");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Renders on mobile", async ({ page, context }) => {
|
|
||||||
await context.addCookies([
|
|
||||||
{
|
|
||||||
url: "http://localhost:8082",
|
|
||||||
name: "trilium-device",
|
|
||||||
value: "mobile"
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
await page.goto("http://localhost:8082");
|
|
||||||
await expect(page.locator(".tree")).toContainText("Trilium Integration Test");
|
|
||||||
});
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { test, expect } from "@playwright/test";
|
|
||||||
|
|
||||||
const expectedVersion = "0.90.3";
|
|
||||||
|
|
||||||
test("Displays update badge when there is a version available", async ({ page }) => {
|
|
||||||
await page.goto("http://localhost:8080");
|
|
||||||
await page.getByRole("button", { name: "" }).click();
|
|
||||||
await page.getByText(`Version ${expectedVersion} is available,`).click();
|
|
||||||
|
|
||||||
const page1 = await page.waitForEvent("popup");
|
|
||||||
expect(page1.url()).toBe(`https://github.com/TriliumNext/Trilium/releases/tag/v${expectedVersion}`);
|
|
||||||
});
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
{
|
|
||||||
"main": "./electron-main.js",
|
|
||||||
"bin": {
|
|
||||||
"trilium": "src/main.js"
|
|
||||||
},
|
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
|
||||||
"server:start-safe": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev nodemon src/main.ts",
|
|
||||||
"server:start-no-dir": "cross-env TRILIUM_ENV=dev nodemon src/main.ts",
|
|
||||||
"server:start-test": "npm run server:switch && rimraf ./data-test && cross-env TRILIUM_DATA_DIR=./data-test 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-no-dir": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_ENV=dev TRILIUM_PORT=37742 electron --inspect=5858 .",
|
|
||||||
"electron:start-nix": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev nix-shell -p electron_33 --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 TRILIUM_PORT=37742 nix-shell -p electron_33 --run \"electron ./electron-main.ts --inspect=5858 .\"",
|
|
||||||
"electron:start-prod-no-dir": "npm run build:prepare-dist && cross-env TRILIUM_ENV=prod 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_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",
|
|
||||||
"docs:build": "typedoc",
|
|
||||||
"test": "npm run client:test && npm run server:test",
|
|
||||||
"client:test": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest --root src/public/app",
|
|
||||||
"client:coverage": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest --root src/public/app --coverage",
|
|
||||||
"test:playwright": "playwright test --workers 1",
|
|
||||||
"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 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:format-check": "eslint -c eslint.format.config.js .",
|
|
||||||
"dev:format-fix": "eslint -c eslint.format.config.js . --fix",
|
|
||||||
"dev:linter-check": "eslint .",
|
|
||||||
"dev:linter-fix": "eslint . --fix",
|
|
||||||
"chore:generate-document": "cross-env nodemon ./bin/generate_document.ts 1000",
|
|
||||||
"chore:generate-openapi": "tsx bin/generate-openapi.js"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@playwright/test": "1.56.1",
|
|
||||||
"@stylistic/eslint-plugin": "5.5.0",
|
|
||||||
"@types/express": "5.0.5",
|
|
||||||
"@types/node": "24.10.0",
|
|
||||||
"@types/yargs": "17.0.34",
|
|
||||||
"@vitest/coverage-v8": "3.2.4",
|
|
||||||
"eslint": "9.39.1",
|
|
||||||
"eslint-plugin-simple-import-sort": "12.1.1",
|
|
||||||
"esm": "3.2.25",
|
|
||||||
"jsdoc": "4.0.5",
|
|
||||||
"lorem-ipsum": "2.0.8",
|
|
||||||
"rcedit": "5.0.0",
|
|
||||||
"rimraf": "6.1.0",
|
|
||||||
"tslib": "2.8.1"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"appdmg": "0.6.6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
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,10 +0,0 @@
|
|||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import etapi from "../support/etapi.js";
|
|
||||||
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 () => {
|
|
||||||
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
||||||
|
|
||||||
const zipFileBuffer = fs.readFileSync(path.resolve(scriptDir, "test-export.zip"));
|
|
||||||
|
|
||||||
const response = await etapi.postEtapiContent("notes/root/import", zipFileBuffer);
|
|
||||||
expect(response.status).toEqual(201);
|
|
||||||
|
|
||||||
const { note, branch } = await response.json();
|
|
||||||
|
|
||||||
expect(note.title).toEqual("test-export");
|
|
||||||
expect(branch.parentNoteId).toEqual("root");
|
|
||||||
|
|
||||||
const content = await (await etapi.getEtapiContent(`notes/${note.noteId}/content`)).text();
|
|
||||||
expect(content).toContain("test export content");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
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", {
|
|
||||||
parentNoteId: "root",
|
|
||||||
type: "text",
|
|
||||||
title: "Hello World!",
|
|
||||||
content: "Content",
|
|
||||||
prefix: "Custom prefix"
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(note.title).toEqual("Hello World!");
|
|
||||||
expect(branch.parentNoteId).toEqual("root");
|
|
||||||
expect(branch.prefix).toEqual("Custom prefix");
|
|
||||||
|
|
||||||
const rNote = await etapi.getEtapi(`notes/${note.noteId}`);
|
|
||||||
expect(rNote.title).toEqual("Hello World!");
|
|
||||||
|
|
||||||
const rContent = await (await etapi.getEtapiContent(`notes/${note.noteId}/content`)).text();
|
|
||||||
expect(rContent).toEqual("Content");
|
|
||||||
|
|
||||||
const rBranch = await etapi.getEtapi(`branches/${branch.branchId}`);
|
|
||||||
expect(rBranch.parentNoteId).toEqual("root");
|
|
||||||
expect(rBranch.prefix).toEqual("Custom prefix");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("patch", async () => {
|
|
||||||
const { note } = await etapi.postEtapi("create-note", {
|
|
||||||
parentNoteId: "root",
|
|
||||||
type: "text",
|
|
||||||
title: "Hello World!",
|
|
||||||
content: "Content"
|
|
||||||
});
|
|
||||||
|
|
||||||
await etapi.patchEtapi(`notes/${note.noteId}`, {
|
|
||||||
title: "new title",
|
|
||||||
type: "code",
|
|
||||||
mime: "text/apl",
|
|
||||||
dateCreated: "2000-01-01 12:34:56.999+0200",
|
|
||||||
utcDateCreated: "2000-01-01 10:34:56.999Z"
|
|
||||||
});
|
|
||||||
|
|
||||||
const rNote = await etapi.getEtapi(`notes/${note.noteId}`);
|
|
||||||
expect(rNote.title).toEqual("new title");
|
|
||||||
expect(rNote.type).toEqual("code");
|
|
||||||
expect(rNote.mime).toEqual("text/apl");
|
|
||||||
expect(rNote.dateCreated).toEqual("2000-01-01 12:34:56.999+0200");
|
|
||||||
expect(rNote.utcDateCreated).toEqual("2000-01-01 10:34:56.999Z");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("update content", async () => {
|
|
||||||
const { note } = await etapi.postEtapi("create-note", {
|
|
||||||
parentNoteId: "root",
|
|
||||||
type: "text",
|
|
||||||
title: "Hello World!",
|
|
||||||
content: "Content"
|
|
||||||
});
|
|
||||||
|
|
||||||
await etapi.putEtapiContent(`notes/${note.noteId}/content`, "new content");
|
|
||||||
|
|
||||||
const rContent = await (await etapi.getEtapiContent(`notes/${note.noteId}/content`)).text();
|
|
||||||
expect(rContent).toEqual("new content");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("create / update binary content", async () => {
|
|
||||||
const { note } = await etapi.postEtapi("create-note", {
|
|
||||||
parentNoteId: "root",
|
|
||||||
type: "file",
|
|
||||||
title: "Hello World!",
|
|
||||||
content: "ZZZ"
|
|
||||||
});
|
|
||||||
|
|
||||||
const updatedContent = crypto.randomBytes(16);
|
|
||||||
|
|
||||||
await etapi.putEtapiContent(`notes/${note.noteId}/content`, updatedContent);
|
|
||||||
|
|
||||||
const rContent = await (await etapi.getEtapiContent(`notes/${note.noteId}/content`)).arrayBuffer();
|
|
||||||
expect(Buffer.from(new Uint8Array(rContent))).toEqual(updatedContent);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("delete note", async () => {
|
|
||||||
const { note } = await etapi.postEtapi("create-note", {
|
|
||||||
parentNoteId: "root",
|
|
||||||
type: "text",
|
|
||||||
title: "Hello World!",
|
|
||||||
content: "Content"
|
|
||||||
});
|
|
||||||
|
|
||||||
await etapi.deleteEtapi(`notes/${note.noteId}`);
|
|
||||||
|
|
||||||
const resp = await etapi.getEtapiResponse(`notes/${note.noteId}`);
|
|
||||||
expect(resp.status).toEqual(404);
|
|
||||||
|
|
||||||
const error = await resp.json();
|
|
||||||
expect(error.status).toEqual(404);
|
|
||||||
expect(error.code).toEqual("NOTE_NOT_FOUND");
|
|
||||||
expect(error.message).toEqual(`Note '${note.noteId}' not found.`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
import { describe, beforeAll, afterAll } from "vitest";
|
|
||||||
|
|
||||||
let etapiAuthToken: string | undefined;
|
|
||||||
|
|
||||||
const getEtapiAuthorizationHeader = (): string => "Basic " + Buffer.from(`etapi:${etapiAuthToken}`).toString("base64");
|
|
||||||
|
|
||||||
const PORT: string = "9999";
|
|
||||||
const HOST: string = "http://localhost:" + PORT;
|
|
||||||
|
|
||||||
type SpecDefinitionsFunc = () => void;
|
|
||||||
|
|
||||||
function describeEtapi(description: string, specDefinitions: SpecDefinitionsFunc): void {
|
|
||||||
describe(description, () => {
|
|
||||||
beforeAll(async () => {});
|
|
||||||
|
|
||||||
afterAll(() => {});
|
|
||||||
|
|
||||||
specDefinitions();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getEtapiResponse(url: string): Promise<Response> {
|
|
||||||
return await fetch(`${HOST}/etapi/${url}`, {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
Authorization: getEtapiAuthorizationHeader()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getEtapi(url: string): Promise<any> {
|
|
||||||
const response = await getEtapiResponse(url);
|
|
||||||
return await processEtapiResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getEtapiContent(url: string): Promise<Response> {
|
|
||||||
const response = await fetch(`${HOST}/etapi/${url}`, {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
Authorization: getEtapiAuthorizationHeader()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
checkStatus(response);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function postEtapi(url: string, data: Record<string, unknown> = {}): Promise<any> {
|
|
||||||
const response = await fetch(`${HOST}/etapi/${url}`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: getEtapiAuthorizationHeader()
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data)
|
|
||||||
});
|
|
||||||
return await processEtapiResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function postEtapiContent(url: string, data: BodyInit): Promise<Response> {
|
|
||||||
const response = await fetch(`${HOST}/etapi/${url}`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/octet-stream",
|
|
||||||
Authorization: getEtapiAuthorizationHeader()
|
|
||||||
},
|
|
||||||
body: data
|
|
||||||
});
|
|
||||||
|
|
||||||
checkStatus(response);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function putEtapi(url: string, data: Record<string, unknown> = {}): Promise<any> {
|
|
||||||
const response = await fetch(`${HOST}/etapi/${url}`, {
|
|
||||||
method: "PUT",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: getEtapiAuthorizationHeader()
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data)
|
|
||||||
});
|
|
||||||
return await processEtapiResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function putEtapiContent(url: string, data?: BodyInit): Promise<Response> {
|
|
||||||
const response = await fetch(`${HOST}/etapi/${url}`, {
|
|
||||||
method: "PUT",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/octet-stream",
|
|
||||||
Authorization: getEtapiAuthorizationHeader()
|
|
||||||
},
|
|
||||||
body: data
|
|
||||||
});
|
|
||||||
|
|
||||||
checkStatus(response);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function patchEtapi(url: string, data: Record<string, unknown> = {}): Promise<any> {
|
|
||||||
const response = await fetch(`${HOST}/etapi/${url}`, {
|
|
||||||
method: "PATCH",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: getEtapiAuthorizationHeader()
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data)
|
|
||||||
});
|
|
||||||
return await processEtapiResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function deleteEtapi(url: string): Promise<any> {
|
|
||||||
const response = await fetch(`${HOST}/etapi/${url}`, {
|
|
||||||
method: "DELETE",
|
|
||||||
headers: {
|
|
||||||
Authorization: getEtapiAuthorizationHeader()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return await processEtapiResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function processEtapiResponse(response: Response): Promise<any> {
|
|
||||||
const text = await response.text();
|
|
||||||
|
|
||||||
if (response.status < 200 || response.status >= 300) {
|
|
||||||
throw new Error(`ETAPI error ${response.status}: ${text}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return text?.trim() ? JSON.parse(text) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkStatus(response: Response): void {
|
|
||||||
if (response.status < 200 || response.status >= 300) {
|
|
||||||
throw new Error(`ETAPI error ${response.status}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
describeEtapi,
|
|
||||||
getEtapi,
|
|
||||||
getEtapiResponse,
|
|
||||||
getEtapiContent,
|
|
||||||
postEtapi,
|
|
||||||
postEtapiContent,
|
|
||||||
putEtapi,
|
|
||||||
putEtapiContent,
|
|
||||||
patchEtapi,
|
|
||||||
deleteEtapi
|
|
||||||
};
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "NodeNext",
|
|
||||||
"declaration": false,
|
|
||||||
"sourceMap": true,
|
|
||||||
"outDir": "./build",
|
|
||||||
"strict": true,
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"lib": ["ES2023"],
|
|
||||||
"downlevelIteration": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"allowJs": true
|
|
||||||
},
|
|
||||||
"include": ["./src/public/app/**/*"],
|
|
||||||
"files": [
|
|
||||||
"./src/public/app/types.d.ts",
|
|
||||||
"./src/public/app/types-lib.d.ts",
|
|
||||||
"./src/types.d.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "build-docs",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "src/main.ts",
|
|
||||||
"scripts": {
|
|
||||||
"start": "tsx ."
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"author": "Elian Doran <contact@eliandoran.me>",
|
|
||||||
"license": "AGPL-3.0-only",
|
|
||||||
"packageManager": "pnpm@10.20.0",
|
|
||||||
"devDependencies": {
|
|
||||||
"@redocly/cli": "2.11.0",
|
|
||||||
"archiver": "7.0.1",
|
|
||||||
"fs-extra": "11.3.2",
|
|
||||||
"react": "19.2.0",
|
|
||||||
"react-dom": "19.2.0",
|
|
||||||
"typedoc": "0.28.14",
|
|
||||||
"typedoc-plugin-missing-exports": "4.1.2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* The backend script API is accessible to code notes with the "JS (backend)" language.
|
|
||||||
*
|
|
||||||
* The entire API is exposed as a single global: {@link api}
|
|
||||||
*
|
|
||||||
* @module Backend Script API
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file creates the entrypoint for TypeDoc that simulates the context from within a
|
|
||||||
* script note on the server side.
|
|
||||||
*
|
|
||||||
* Make sure to keep in line with backend's `script_context.ts`.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export type { default as AbstractBeccaEntity } from "../../server/src/becca/entities/abstract_becca_entity.js";
|
|
||||||
export type { default as BAttachment } from "../../server/src/becca/entities/battachment.js";
|
|
||||||
export type { default as BAttribute } from "../../server/src/becca/entities/battribute.js";
|
|
||||||
export type { default as BBranch } from "../../server/src/becca/entities/bbranch.js";
|
|
||||||
export type { default as BEtapiToken } from "../../server/src/becca/entities/betapi_token.js";
|
|
||||||
export type { BNote };
|
|
||||||
export type { default as BOption } from "../../server/src/becca/entities/boption.js";
|
|
||||||
export type { default as BRecentNote } from "../../server/src/becca/entities/brecent_note.js";
|
|
||||||
export type { default as BRevision } from "../../server/src/becca/entities/brevision.js";
|
|
||||||
|
|
||||||
import BNote from "../../server/src/becca/entities/bnote.js";
|
|
||||||
import BackendScriptApi, { type Api } from "../../server/src/services/backend_script_api.js";
|
|
||||||
|
|
||||||
export type { Api };
|
|
||||||
|
|
||||||
const fakeNote = new BNote();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `api` global variable allows access to the backend script API, which is documented in {@link Api}.
|
|
||||||
*/
|
|
||||||
export const api: Api = new BackendScriptApi(fakeNote, {});
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
process.env.TRILIUM_INTEGRATION_TEST = "memory-no-store";
|
|
||||||
process.env.TRILIUM_RESOURCE_DIR = "../server/src";
|
|
||||||
process.env.NODE_ENV = "development";
|
|
||||||
|
|
||||||
import cls from "@triliumnext/server/src/services/cls.js";
|
|
||||||
import { dirname, join, resolve } from "path";
|
|
||||||
import * as fs from "fs/promises";
|
|
||||||
import * as fsExtra from "fs-extra";
|
|
||||||
import archiver from "archiver";
|
|
||||||
import { WriteStream } from "fs";
|
|
||||||
import { execSync } from "child_process";
|
|
||||||
import BuildContext from "./context.js";
|
|
||||||
|
|
||||||
const DOCS_ROOT = "../../../docs";
|
|
||||||
const OUTPUT_DIR = "../../site";
|
|
||||||
|
|
||||||
async function importAndExportDocs(sourcePath: string, outputSubDir: string) {
|
|
||||||
const note = await importData(sourcePath);
|
|
||||||
|
|
||||||
// Use a meaningful name for the temporary zip file
|
|
||||||
const zipName = outputSubDir || "user-guide";
|
|
||||||
const zipFilePath = `output-${zipName}.zip`;
|
|
||||||
try {
|
|
||||||
const { exportToZip } = (await import("@triliumnext/server/src/services/export/zip.js")).default;
|
|
||||||
const branch = note.getParentBranches()[0];
|
|
||||||
const taskContext = new (await import("@triliumnext/server/src/services/task_context.js")).default(
|
|
||||||
"no-progress-reporting",
|
|
||||||
"export",
|
|
||||||
null
|
|
||||||
);
|
|
||||||
const fileOutputStream = fsExtra.createWriteStream(zipFilePath);
|
|
||||||
await exportToZip(taskContext, branch, "share", fileOutputStream);
|
|
||||||
await waitForStreamToFinish(fileOutputStream);
|
|
||||||
|
|
||||||
// Output to root directory if outputSubDir is empty, otherwise to subdirectory
|
|
||||||
const outputPath = outputSubDir ? join(OUTPUT_DIR, outputSubDir) : OUTPUT_DIR;
|
|
||||||
await extractZip(zipFilePath, outputPath);
|
|
||||||
} finally {
|
|
||||||
if (await fsExtra.exists(zipFilePath)) {
|
|
||||||
await fsExtra.rm(zipFilePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function buildDocsInner() {
|
|
||||||
const i18n = await import("@triliumnext/server/src/services/i18n.js");
|
|
||||||
await i18n.initializeTranslations();
|
|
||||||
|
|
||||||
const sqlInit = (await import("../../server/src/services/sql_init.js")).default;
|
|
||||||
await sqlInit.createInitialDatabase(true);
|
|
||||||
|
|
||||||
// Wait for becca to be loaded before importing data
|
|
||||||
const beccaLoader = await import("../../server/src/becca/becca_loader.js");
|
|
||||||
await beccaLoader.beccaLoaded;
|
|
||||||
|
|
||||||
// Build User Guide
|
|
||||||
console.log("Building User Guide...");
|
|
||||||
await importAndExportDocs(join(__dirname, DOCS_ROOT, "User Guide"), "user-guide");
|
|
||||||
|
|
||||||
// Build Developer Guide
|
|
||||||
console.log("Building Developer Guide...");
|
|
||||||
await importAndExportDocs(join(__dirname, DOCS_ROOT, "Developer Guide"), "developer-guide");
|
|
||||||
|
|
||||||
// Copy favicon.
|
|
||||||
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "favicon.ico"));
|
|
||||||
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "user-guide", "favicon.ico"));
|
|
||||||
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "developer-guide", "favicon.ico"));
|
|
||||||
|
|
||||||
console.log("Documentation built successfully!");
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function importData(path: string) {
|
|
||||||
const buffer = await createImportZip(path);
|
|
||||||
const importService = (await import("../../server/src/services/import/zip.js")).default;
|
|
||||||
const TaskContext = (await import("../../server/src/services/task_context.js")).default;
|
|
||||||
const context = new TaskContext("no-progress-reporting", "importNotes", null);
|
|
||||||
const becca = (await import("../../server/src/becca/becca.js")).default;
|
|
||||||
|
|
||||||
const rootNote = becca.getRoot();
|
|
||||||
if (!rootNote) {
|
|
||||||
throw new Error("Missing root note for import.");
|
|
||||||
}
|
|
||||||
return await importService.importZip(context, buffer, rootNote, {
|
|
||||||
preserveIds: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createImportZip(path: string) {
|
|
||||||
const inputFile = "input.zip";
|
|
||||||
const archive = archiver("zip", {
|
|
||||||
zlib: { level: 0 }
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("Archive path is ", resolve(path))
|
|
||||||
archive.directory(path, "/");
|
|
||||||
|
|
||||||
const outputStream = fsExtra.createWriteStream(inputFile);
|
|
||||||
archive.pipe(outputStream);
|
|
||||||
archive.finalize();
|
|
||||||
await waitForStreamToFinish(outputStream);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await fsExtra.readFile(inputFile);
|
|
||||||
} finally {
|
|
||||||
await fsExtra.rm(inputFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function waitForStreamToFinish(stream: WriteStream) {
|
|
||||||
return new Promise<void>((res, rej) => {
|
|
||||||
stream.on("finish", () => res());
|
|
||||||
stream.on("error", (err) => rej(err));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function extractZip(zipFilePath: string, outputPath: string, ignoredFiles?: Set<string>) {
|
|
||||||
const { readZipFile, readContent } = (await import("@triliumnext/server/src/services/import/zip.js"));
|
|
||||||
await readZipFile(await fs.readFile(zipFilePath), async (zip, entry) => {
|
|
||||||
// We ignore directories since they can appear out of order anyway.
|
|
||||||
if (!entry.fileName.endsWith("/") && !ignoredFiles?.has(entry.fileName)) {
|
|
||||||
const destPath = join(outputPath, entry.fileName);
|
|
||||||
const fileContent = await readContent(zip, entry);
|
|
||||||
|
|
||||||
await fsExtra.mkdirs(dirname(destPath));
|
|
||||||
await fs.writeFile(destPath, fileContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
zip.readEntry();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function buildDocs({ gitRootDir }: BuildContext) {
|
|
||||||
// Build the share theme.
|
|
||||||
execSync(`pnpm run --filter share-theme build`, {
|
|
||||||
stdio: "inherit",
|
|
||||||
cwd: gitRootDir
|
|
||||||
});
|
|
||||||
|
|
||||||
// Trigger the actual build.
|
|
||||||
await new Promise((res, rej) => {
|
|
||||||
cls.init(() => {
|
|
||||||
buildDocsInner()
|
|
||||||
.catch(rej)
|
|
||||||
.then(res);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export default interface BuildContext {
|
|
||||||
gitRootDir: string;
|
|
||||||
baseDir: string;
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* The front script API is accessible to code notes with the "JS (frontend)" language.
|
|
||||||
*
|
|
||||||
* The entire API is exposed as a single global: {@link api}
|
|
||||||
*
|
|
||||||
* @module Frontend Script API
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file creates the entrypoint for TypeDoc that simulates the context from within a
|
|
||||||
* script note.
|
|
||||||
*
|
|
||||||
* Make sure to keep in line with frontend's `script_context.ts`.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export type { default as BasicWidget } from "../../client/src/widgets/basic_widget.js";
|
|
||||||
export type { default as FAttachment } from "../../client/src/entities/fattachment.js";
|
|
||||||
export type { default as FAttribute } from "../../client/src/entities/fattribute.js";
|
|
||||||
export type { default as FBranch } from "../../client/src/entities/fbranch.js";
|
|
||||||
export type { default as FNote } from "../../client/src/entities/fnote.js";
|
|
||||||
export type { Api } from "../../client/src/services/frontend_script_api.js";
|
|
||||||
export type { default as NoteContextAwareWidget } from "../../client/src/widgets/note_context_aware_widget.js";
|
|
||||||
export type { default as RightPanelWidget } from "../../client/src/widgets/right_panel_widget.js";
|
|
||||||
|
|
||||||
import FrontendScriptApi, { type Api } from "../../client/src/services/frontend_script_api.js";
|
|
||||||
|
|
||||||
//@ts-expect-error
|
|
||||||
export const api: Api = new FrontendScriptApi();
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="refresh" content="0; url=/user-guide">
|
|
||||||
<title>Redirecting...</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p>If you are not redirected automatically, <a href="/user-guide">click here</a>.</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import { join } from "path";
|
|
||||||
import BuildContext from "./context";
|
|
||||||
import buildSwagger from "./swagger";
|
|
||||||
import { cpSync, existsSync, mkdirSync, rmSync } from "fs";
|
|
||||||
import buildDocs from "./build-docs";
|
|
||||||
import buildScriptApi from "./script-api";
|
|
||||||
|
|
||||||
const context: BuildContext = {
|
|
||||||
gitRootDir: join(__dirname, "../../../"),
|
|
||||||
baseDir: join(__dirname, "../../../site")
|
|
||||||
};
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
// Clean input dir.
|
|
||||||
if (existsSync(context.baseDir)) {
|
|
||||||
rmSync(context.baseDir, { recursive: true });
|
|
||||||
}
|
|
||||||
mkdirSync(context.baseDir);
|
|
||||||
|
|
||||||
// Start building.
|
|
||||||
await buildDocs(context);
|
|
||||||
buildSwagger(context);
|
|
||||||
buildScriptApi(context);
|
|
||||||
|
|
||||||
// Copy index and 404 files.
|
|
||||||
cpSync(join(__dirname, "index.html"), join(context.baseDir, "index.html"));
|
|
||||||
cpSync(join(context.baseDir, "user-guide/404.html"), join(context.baseDir, "404.html"));
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import { execSync } from "child_process";
|
|
||||||
import BuildContext from "./context";
|
|
||||||
import { join } from "path";
|
|
||||||
|
|
||||||
export default function buildScriptApi({ baseDir, gitRootDir }: BuildContext) {
|
|
||||||
// Generate types
|
|
||||||
execSync(`pnpm typecheck`, { stdio: "inherit", cwd: gitRootDir });
|
|
||||||
|
|
||||||
for (const config of [ "backend", "frontend" ]) {
|
|
||||||
const outDir = join(baseDir, "script-api", config);
|
|
||||||
execSync(`pnpm typedoc --options typedoc.${config}.json --html "${outDir}"`, {
|
|
||||||
stdio: "inherit"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import BuildContext from "./context";
|
|
||||||
import { join } from "path";
|
|
||||||
import { execSync } from "child_process";
|
|
||||||
import { mkdirSync } from "fs";
|
|
||||||
|
|
||||||
interface BuildInfo {
|
|
||||||
specPath: string;
|
|
||||||
outDir: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DIR_PREFIX = "rest-api";
|
|
||||||
|
|
||||||
const buildInfos: BuildInfo[] = [
|
|
||||||
{
|
|
||||||
// Paths are relative to Git root.
|
|
||||||
specPath: "apps/server/internal.openapi.yaml",
|
|
||||||
outDir: `${DIR_PREFIX}/internal`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
specPath: "apps/server/etapi.openapi.yaml",
|
|
||||||
outDir: `${DIR_PREFIX}/etapi`
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function buildSwagger({ baseDir, gitRootDir }: BuildContext) {
|
|
||||||
for (const { specPath, outDir } of buildInfos) {
|
|
||||||
const absSpecPath = join(gitRootDir, specPath);
|
|
||||||
const targetDir = join(baseDir, outDir);
|
|
||||||
mkdirSync(targetDir, { recursive: true });
|
|
||||||
execSync(`pnpm redocly build-docs ${absSpecPath} -o ${targetDir}/index.html`, { stdio: "inherit" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tsconfig.base.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "ESNext",
|
|
||||||
"moduleResolution": "bundler",
|
|
||||||
"target": "ES2020",
|
|
||||||
"outDir": "dist",
|
|
||||||
"strict": false,
|
|
||||||
"types": [
|
|
||||||
"node",
|
|
||||||
"express"
|
|
||||||
],
|
|
||||||
"rootDir": "src",
|
|
||||||
"tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo"
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src/**/*.ts",
|
|
||||||
"../server/src/*.d.ts"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"eslint.config.js",
|
|
||||||
"eslint.config.cjs",
|
|
||||||
"eslint.config.mjs"
|
|
||||||
],
|
|
||||||
"references": [
|
|
||||||
{
|
|
||||||
"path": "../server/tsconfig.app.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "../desktop/tsconfig.app.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "../client/tsconfig.app.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tsconfig.base.json",
|
|
||||||
"include": [],
|
|
||||||
"references": [
|
|
||||||
{
|
|
||||||
"path": "../server"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "../client"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.app.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://typedoc.org/schema.json",
|
|
||||||
"name": "Trilium Backend API",
|
|
||||||
"entryPoints": [
|
|
||||||
"src/backend_script_entrypoint.ts"
|
|
||||||
],
|
|
||||||
"plugin": [
|
|
||||||
"typedoc-plugin-missing-exports"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://typedoc.org/schema.json",
|
|
||||||
"name": "Trilium Frontend API",
|
|
||||||
"entryPoints": [
|
|
||||||
"src/frontend_script_entrypoint.ts"
|
|
||||||
],
|
|
||||||
"plugin": [
|
|
||||||
"typedoc-plugin-missing-exports"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# The development license key for premium CKEditor features.
|
|
||||||
# Note: This key must only be used for the Trilium Notes project.
|
|
||||||
VITE_CKEDITOR_KEY=eyJhbGciOiJFUzI1NiJ9.eyJleHAiOjE3ODcyNzA0MDAsImp0aSI6IjkyMWE1MWNlLTliNDMtNGRlMC1iOTQwLTc5ZjM2MDBkYjg1NyIsImRpc3RyaWJ1dGlvbkNoYW5uZWwiOiJ0cmlsaXVtIiwiZmVhdHVyZXMiOlsiVFJJTElVTSJdLCJ2YyI6ImU4YzRhMjBkIn0.hny77p-U4-jTkoqbwPytrEar5ylGCWBN7Ez3SlB8i6_mJCBIeCSTOlVQk_JMiOEq3AGykUMHzWXzjdMFwgniOw
|
|
||||||
VITE_CKEDITOR_ENABLE_INSPECTOR=false
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
VITE_CKEDITOR_ENABLE_INSPECTOR=false
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user