Merge branch 'develop' into ai-llm-integration
@ -1,10 +1,37 @@
|
|||||||
.git
|
# ignored Files
|
||||||
.idea
|
.dockerignore
|
||||||
|
.editorconfig
|
||||||
|
.git*
|
||||||
|
.prettier*
|
||||||
|
electron*
|
||||||
|
entitlements.plist
|
||||||
|
forge.config.cjs
|
||||||
|
nodemon.json
|
||||||
|
renovate.json
|
||||||
|
trilium.iml
|
||||||
|
Dockerfile
|
||||||
|
Dockerfile.*
|
||||||
|
npm-debug.log
|
||||||
|
/src/**/*.spec.ts
|
||||||
|
|
||||||
|
# ignored folders
|
||||||
|
/.cache
|
||||||
|
/.git
|
||||||
|
/.github
|
||||||
|
/.idea
|
||||||
|
/.vscode
|
||||||
/bin
|
/bin
|
||||||
|
/build
|
||||||
/dist
|
/dist
|
||||||
/docs
|
/docs
|
||||||
/npm-debug.log
|
/dump-db
|
||||||
node_modules
|
/e2e
|
||||||
|
/integration-tests
|
||||||
|
/spec
|
||||||
|
/test
|
||||||
|
/test-etapi
|
||||||
|
/node_modules
|
||||||
|
|
||||||
src/**/*.ts
|
|
||||||
!src/services/asset_path.ts
|
# exceptions
|
||||||
|
!/bin/copy-dist.ts
|
||||||
24
.github/workflows/dev.yml
vendored
@ -44,16 +44,6 @@ jobs:
|
|||||||
- test_dev
|
- test_dev
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Set up node & dependencies
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
cache: "npm"
|
|
||||||
- run: npm ci
|
|
||||||
- name: Run the TypeScript build
|
|
||||||
run: npx tsc
|
|
||||||
- name: Create server-package.json
|
|
||||||
run: cat package.json | grep -v electron > server-package.json
|
|
||||||
- uses: docker/setup-buildx-action@v3
|
- uses: docker/setup-buildx-action@v3
|
||||||
- uses: docker/build-push-action@v6
|
- uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
@ -82,20 +72,6 @@ jobs:
|
|||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Set up node & dependencies
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
cache: "npm"
|
|
||||||
|
|
||||||
- run: npm ci
|
|
||||||
|
|
||||||
- name: Run the TypeScript build
|
|
||||||
run: npx tsc
|
|
||||||
|
|
||||||
- name: Create server-package.json
|
|
||||||
run: cat package.json | grep -v electron > server-package.json
|
|
||||||
|
|
||||||
- name: Build and export to Docker
|
- name: Build and export to Docker
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
15
.github/workflows/main-docker.yml
vendored
@ -57,9 +57,6 @@ jobs:
|
|||||||
- name: Run the TypeScript build
|
- name: Run the TypeScript build
|
||||||
run: npx tsc
|
run: npx tsc
|
||||||
|
|
||||||
- name: Create server-package.json
|
|
||||||
run: cat package.json | grep -v electron > server-package.json
|
|
||||||
|
|
||||||
- name: Build and export to Docker
|
- name: Build and export to Docker
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
@ -154,18 +151,6 @@ jobs:
|
|||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
|
||||||
- name: Set up node & dependencies
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
cache: "npm"
|
|
||||||
- run: npm ci
|
|
||||||
- name: Run the TypeScript build
|
|
||||||
run: npx tsc
|
|
||||||
- name: Create server-package.json
|
|
||||||
run: cat package.json | grep -v electron > server-package.json
|
|
||||||
|
|
||||||
- name: Login to GHCR
|
- name: Login to GHCR
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
@ -2,4 +2,5 @@
|
|||||||
*.md
|
*.md
|
||||||
*.yml
|
*.yml
|
||||||
libraries/*
|
libraries/*
|
||||||
docs/*
|
docs/*
|
||||||
|
src/public/app/doc_notes/**/*
|
||||||
6
.vscode/extensions.json
vendored
@ -1,3 +1,7 @@
|
|||||||
{
|
{
|
||||||
"recommendations": ["lokalise.i18n-ally", "editorconfig.editorconfig"]
|
"recommendations": [
|
||||||
|
"lokalise.i18n-ally",
|
||||||
|
"editorconfig.editorconfig",
|
||||||
|
"vitest.explorer"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
4
.vscode/launch.json
vendored
@ -5,8 +5,8 @@
|
|||||||
{
|
{
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"internalConsoleOptions": "neverOpen",
|
"internalConsoleOptions": "neverOpen",
|
||||||
"name": "nodemon server:start",
|
"name": "nodemon start-server",
|
||||||
"program": "${workspaceFolder}/src/main",
|
"program": "${workspaceFolder}/src/www",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"restart": true,
|
"restart": true,
|
||||||
"runtimeExecutable": "nodemon",
|
"runtimeExecutable": "nodemon",
|
||||||
|
|||||||
9
.vscode/settings.json
vendored
@ -19,5 +19,12 @@
|
|||||||
"[css]": {
|
"[css]": {
|
||||||
"editor.defaultFormatter": "vscode.css-language-features"
|
"editor.defaultFormatter": "vscode.css-language-features"
|
||||||
},
|
},
|
||||||
"npm.exclude": ["**/build", "**/dist", "**/out/**"]
|
"npm.exclude": [
|
||||||
|
"**/build",
|
||||||
|
"**/dist",
|
||||||
|
"**/out/**"
|
||||||
|
],
|
||||||
|
"[xml]": {
|
||||||
|
"editor.defaultFormatter": "redhat.vscode-xml"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
72
Dockerfile
@ -1,62 +1,46 @@
|
|||||||
# Build stage
|
# Build stage
|
||||||
FROM node:22.14.0-bullseye-slim AS builder
|
FROM node:22.14.0-bullseye-slim AS builder
|
||||||
|
|
||||||
# Configure build dependencies in a single layer
|
WORKDIR /usr/src/app/build
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
||||||
autoconf \
|
|
||||||
automake \
|
|
||||||
g++ \
|
|
||||||
gcc \
|
|
||||||
libtool \
|
|
||||||
make \
|
|
||||||
nasm \
|
|
||||||
libpng-dev \
|
|
||||||
python3 \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
|
|
||||||
# Copy only necessary files for build
|
# Copy only necessary files for build
|
||||||
COPY . .
|
COPY . .
|
||||||
COPY server-package.json package.json
|
|
||||||
|
|
||||||
# Build and cleanup in a single layer
|
# Build and cleanup in a single layer
|
||||||
RUN cp -R build/src/* src/. && \
|
RUN npm ci && \
|
||||||
cp build/docker_healthcheck.js . && \
|
npm run build:prepare-dist && \
|
||||||
rm docker_healthcheck.ts && \
|
|
||||||
npm install && \
|
|
||||||
npm run build:webpack && \
|
|
||||||
npm prune --omit=dev && \
|
|
||||||
npm cache clean --force && \
|
npm cache clean --force && \
|
||||||
cp -r src/public/app/doc_notes src/public/app-dist/. && \
|
rm -rf dist/node_modules && \
|
||||||
rm -rf src/public/app/* && \
|
mv dist/* \
|
||||||
mkdir -p src/public/app/services && \
|
start-docker.sh \
|
||||||
cp -r build/src/public/app/services/mime_type_definitions.js src/public/app/services/mime_type_definitions.js && \
|
/usr/src/app/ && \
|
||||||
rm src/services/asset_path.ts && \
|
rm -rf \
|
||||||
rm -r build
|
/usr/src/app/build \
|
||||||
|
/tmp/node-compile-cache
|
||||||
|
|
||||||
|
#TODO: improve node_modules handling in copy-dist/Dockerfile -> remove duplicated work
|
||||||
|
# currently copy-dist will copy certain node_module folders, but in the Dockerfile we delete them again (to keep image size down),
|
||||||
|
# as we install necessary dependencies in runtime buildstage anyways
|
||||||
|
|
||||||
# Runtime stage
|
# Runtime stage
|
||||||
FROM node:22.14.0-bullseye-slim
|
FROM node:22.14.0-bullseye-slim
|
||||||
|
|
||||||
# Install only runtime dependencies
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
||||||
gosu \
|
|
||||||
&& rm -rf /var/lib/apt/lists/* && \
|
|
||||||
rm -rf /var/cache/apt/*
|
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
# Copy only necessary files from builder
|
# Install only runtime dependencies
|
||||||
COPY --from=builder /usr/src/app/node_modules ./node_modules
|
RUN apt-get update && \
|
||||||
COPY --from=builder /usr/src/app/src ./src
|
apt-get install -y --no-install-recommends \
|
||||||
COPY --from=builder /usr/src/app/db ./db
|
gosu && \
|
||||||
COPY --from=builder /usr/src/app/docker_healthcheck.js .
|
rm -rf \
|
||||||
COPY --from=builder /usr/src/app/start-docker.sh .
|
/var/lib/apt/lists/* \
|
||||||
COPY --from=builder /usr/src/app/package.json .
|
/var/cache/apt/*
|
||||||
COPY --from=builder /usr/src/app/config-sample.ini .
|
|
||||||
COPY --from=builder /usr/src/app/images ./images
|
COPY --from=builder /usr/src/app ./
|
||||||
COPY --from=builder /usr/src/app/translations ./translations
|
|
||||||
COPY --from=builder /usr/src/app/libraries ./libraries
|
RUN sed -i "/electron/d" package.json && \
|
||||||
|
npm ci --omit=dev && \
|
||||||
|
npm cache clean --force && \
|
||||||
|
rm -rf /tmp/node-compile-cache
|
||||||
|
|
||||||
# Configure container
|
# Configure container
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|||||||
@ -1,38 +1,26 @@
|
|||||||
# Build stage
|
# Build stage
|
||||||
FROM node:22.14.0-alpine AS builder
|
FROM node:22.14.0-alpine AS builder
|
||||||
|
|
||||||
# Configure build dependencies
|
WORKDIR /usr/src/app/build
|
||||||
RUN apk add --no-cache --virtual .build-dependencies \
|
|
||||||
autoconf \
|
|
||||||
automake \
|
|
||||||
g++ \
|
|
||||||
gcc \
|
|
||||||
libtool \
|
|
||||||
make \
|
|
||||||
nasm \
|
|
||||||
libpng-dev \
|
|
||||||
python3
|
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
|
|
||||||
# Copy only necessary files for build
|
# Copy only necessary files for build
|
||||||
COPY . .
|
COPY . .
|
||||||
COPY server-package.json package.json
|
|
||||||
|
|
||||||
# Build and cleanup in a single layer
|
# Build and cleanup in a single layer
|
||||||
RUN cp -R build/src/* src/. && \
|
RUN npm ci && \
|
||||||
cp build/docker_healthcheck.js . && \
|
npm run build:prepare-dist && \
|
||||||
rm docker_healthcheck.ts && \
|
|
||||||
npm install && \
|
|
||||||
npm run build:webpack && \
|
|
||||||
npm prune --omit=dev && \
|
|
||||||
npm cache clean --force && \
|
npm cache clean --force && \
|
||||||
cp -r src/public/app/doc_notes src/public/app-dist/. && \
|
rm -rf dist/node_modules && \
|
||||||
rm -rf src/public/app && \
|
mv dist/* \
|
||||||
mkdir -p src/public/app/services && \
|
start-docker.sh \
|
||||||
cp -r build/src/public/app/services/mime_type_definitions.js src/public/app/services/mime_type_definitions.js && \
|
/usr/src/app/ && \
|
||||||
rm src/services/asset_path.ts && \
|
rm -rf \
|
||||||
rm -r build
|
/usr/src/app/build \
|
||||||
|
/tmp/node-compile-cache
|
||||||
|
|
||||||
|
#TODO: improve node_modules handling in copy-dist/Dockerfile -> remove duplicated work
|
||||||
|
# currently copy-dist will copy certain node_module folders, but in the Dockerfile we delete them again (to keep image size down),
|
||||||
|
# as we install necessary dependencies in runtime buildstage anyways
|
||||||
|
|
||||||
# Runtime stage
|
# Runtime stage
|
||||||
FROM node:22.14.0-alpine
|
FROM node:22.14.0-alpine
|
||||||
@ -42,17 +30,12 @@ RUN apk add --no-cache su-exec shadow
|
|||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
# Copy only necessary files from builder
|
COPY --from=builder /usr/src/app ./
|
||||||
COPY --from=builder /usr/src/app/node_modules ./node_modules
|
|
||||||
COPY --from=builder /usr/src/app/src ./src
|
RUN sed -i "/electron/d" package.json && \
|
||||||
COPY --from=builder /usr/src/app/db ./db
|
npm ci --omit=dev && \
|
||||||
COPY --from=builder /usr/src/app/docker_healthcheck.js .
|
npm cache clean --force && \
|
||||||
COPY --from=builder /usr/src/app/start-docker.sh .
|
rm -rf /tmp/node-compile-cache
|
||||||
COPY --from=builder /usr/src/app/package.json .
|
|
||||||
COPY --from=builder /usr/src/app/config-sample.ini .
|
|
||||||
COPY --from=builder /usr/src/app/images ./images
|
|
||||||
COPY --from=builder /usr/src/app/translations ./translations
|
|
||||||
COPY --from=builder /usr/src/app/libraries ./libraries
|
|
||||||
|
|
||||||
# Add application user
|
# Add application user
|
||||||
RUN adduser -s /bin/false node; exit 0
|
RUN adduser -s /bin/false node; exit 0
|
||||||
|
|||||||
@ -5,11 +5,6 @@ set -e # Fail on any command error
|
|||||||
VERSION=`jq -r ".version" package.json`
|
VERSION=`jq -r ".version" package.json`
|
||||||
SERIES=${VERSION:0:4}-latest
|
SERIES=${VERSION:0:4}-latest
|
||||||
|
|
||||||
cat package.json | grep -v electron > server-package.json
|
|
||||||
|
|
||||||
echo "Compiling typescript..."
|
|
||||||
npx tsc
|
|
||||||
|
|
||||||
sudo docker build -t triliumnext/notes:$VERSION --network host -t triliumnext/notes:$SERIES .
|
sudo docker build -t triliumnext/notes:$VERSION --network host -t triliumnext/notes:$SERIES .
|
||||||
|
|
||||||
if [[ $VERSION != *"beta"* ]]; then
|
if [[ $VERSION != *"beta"* ]]; then
|
||||||
|
|||||||
@ -66,8 +66,6 @@ chmod 755 $PKG_DIR/trilium.sh
|
|||||||
cp bin/tpl/anonymize-database.sql $PKG_DIR/
|
cp bin/tpl/anonymize-database.sql $PKG_DIR/
|
||||||
|
|
||||||
cp -r translations $PKG_DIR/
|
cp -r translations $PKG_DIR/
|
||||||
cp -r dump-db $PKG_DIR/
|
|
||||||
rm -rf $PKG_DIR/dump-db/node_modules
|
|
||||||
|
|
||||||
VERSION=`jq -r ".version" package.json`
|
VERSION=`jq -r ".version" package.json`
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,6 @@ import fs from "fs-extra";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
const DEST_DIR = "./dist";
|
const DEST_DIR = "./dist";
|
||||||
const DEST_DIR_SRC = path.join(DEST_DIR, "src");
|
|
||||||
const DEST_DIR_NODE_MODULES = path.join(DEST_DIR, "node_modules");
|
|
||||||
|
|
||||||
const VERBOSE = process.env.VERBOSE;
|
const VERBOSE = process.env.VERBOSE;
|
||||||
|
|
||||||
@ -13,43 +11,37 @@ function log(...args: any[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function copyNodeModuleFileOrFolder(source: string) {
|
function copyNodeModuleFileOrFolder(source: string) {
|
||||||
const adjustedSource = source.substring(13);
|
const destination = path.join(DEST_DIR, source);
|
||||||
const destination = path.join(DEST_DIR_NODE_MODULES, adjustedSource);
|
|
||||||
|
|
||||||
log(`Copying ${source} to ${destination}`);
|
log(`Copying ${source} to ${destination}`);
|
||||||
await fs.ensureDir(path.dirname(destination));
|
fs.ensureDirSync(path.dirname(destination));
|
||||||
await fs.copy(source, destination);
|
fs.copySync(source, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
const copy = async () => {
|
try {
|
||||||
for (const srcFile of fs.readdirSync("build")) {
|
|
||||||
const destFile = path.join(DEST_DIR, path.basename(srcFile));
|
|
||||||
log(`Copying source ${srcFile} -> ${destFile}.`);
|
|
||||||
fs.copySync(path.join("build", srcFile), destFile, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
const filesToCopy = [
|
const assetsToCopy = new Set([
|
||||||
"config-sample.ini",
|
"./images",
|
||||||
"tsconfig.webpack.json",
|
"./libraries",
|
||||||
|
"./translations",
|
||||||
|
"./db",
|
||||||
|
"./config-sample.ini",
|
||||||
|
"./package-lock.json",
|
||||||
|
"./package.json",
|
||||||
|
"./src/views/",
|
||||||
"./src/etapi/etapi.openapi.yaml",
|
"./src/etapi/etapi.openapi.yaml",
|
||||||
"./src/routes/api/openapi.json"
|
"./src/routes/api/openapi.json",
|
||||||
];
|
"./src/public/icon.png",
|
||||||
for (const file of filesToCopy) {
|
"./src/public/manifest.webmanifest",
|
||||||
log(`Copying ${file}`);
|
"./src/public/robots.txt",
|
||||||
await fs.copy(file, path.join(DEST_DIR, file));
|
"./src/public/fonts",
|
||||||
}
|
"./src/public/stylesheets",
|
||||||
|
"./src/public/translations"
|
||||||
|
]);
|
||||||
|
|
||||||
const dirsToCopy = ["images", "libraries", "translations", "db"];
|
for (const asset of assetsToCopy) {
|
||||||
for (const dir of dirsToCopy) {
|
log(`Copying ${asset}`);
|
||||||
log(`Copying ${dir}`);
|
fs.copySync(asset, path.join(DEST_DIR, asset));
|
||||||
await fs.copy(dir, path.join(DEST_DIR, dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
const srcDirsToCopy = ["./src/public", "./src/views", "./build"];
|
|
||||||
for (const dir of srcDirsToCopy) {
|
|
||||||
log(`Copying ${dir}`);
|
|
||||||
await fs.copy(dir, path.join(DEST_DIR_SRC, path.basename(dir)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,10 +50,10 @@ const copy = async () => {
|
|||||||
const publicDirsToCopy = ["./src/public/app/doc_notes"];
|
const publicDirsToCopy = ["./src/public/app/doc_notes"];
|
||||||
const PUBLIC_DIR = path.join(DEST_DIR, "src", "public", "app-dist");
|
const PUBLIC_DIR = path.join(DEST_DIR, "src", "public", "app-dist");
|
||||||
for (const dir of publicDirsToCopy) {
|
for (const dir of publicDirsToCopy) {
|
||||||
await fs.copy(dir, path.join(PUBLIC_DIR, path.basename(dir)));
|
fs.copySync(dir, path.join(PUBLIC_DIR, path.basename(dir)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeModulesFile = [
|
const nodeModulesFile = new Set([
|
||||||
"node_modules/react/umd/react.production.min.js",
|
"node_modules/react/umd/react.production.min.js",
|
||||||
"node_modules/react/umd/react.development.js",
|
"node_modules/react/umd/react.development.js",
|
||||||
"node_modules/react-dom/umd/react-dom.production.min.js",
|
"node_modules/react-dom/umd/react-dom.production.min.js",
|
||||||
@ -71,13 +63,9 @@ const copy = async () => {
|
|||||||
"node_modules/katex/dist/contrib/auto-render.min.js",
|
"node_modules/katex/dist/contrib/auto-render.min.js",
|
||||||
"node_modules/@highlightjs/cdn-assets/highlight.min.js",
|
"node_modules/@highlightjs/cdn-assets/highlight.min.js",
|
||||||
"node_modules/@mind-elixir/node-menu/dist/node-menu.umd.cjs"
|
"node_modules/@mind-elixir/node-menu/dist/node-menu.umd.cjs"
|
||||||
];
|
]);
|
||||||
|
|
||||||
for (const file of nodeModulesFile) {
|
const nodeModulesFolder = new Set([
|
||||||
await copyNodeModuleFileOrFolder(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
const nodeModulesFolder = [
|
|
||||||
"node_modules/@excalidraw/excalidraw/dist/",
|
"node_modules/@excalidraw/excalidraw/dist/",
|
||||||
"node_modules/katex/dist/",
|
"node_modules/katex/dist/",
|
||||||
"node_modules/dayjs/",
|
"node_modules/dayjs/",
|
||||||
@ -104,13 +92,15 @@ const copy = async () => {
|
|||||||
"node_modules/@highlightjs/cdn-assets/languages",
|
"node_modules/@highlightjs/cdn-assets/languages",
|
||||||
"node_modules/@highlightjs/cdn-assets/styles",
|
"node_modules/@highlightjs/cdn-assets/styles",
|
||||||
"node_modules/leaflet/dist"
|
"node_modules/leaflet/dist"
|
||||||
];
|
]);
|
||||||
|
|
||||||
for (const folder of nodeModulesFolder) {
|
|
||||||
await copyNodeModuleFileOrFolder(folder);
|
|
||||||
|
for (const nodeModuleItem of [...nodeModulesFile, ...nodeModulesFolder]) {
|
||||||
|
copyNodeModuleFileOrFolder(nodeModuleItem);
|
||||||
}
|
}
|
||||||
};
|
console.log("Copying complete!")
|
||||||
|
|
||||||
copy()
|
} catch(err) {
|
||||||
.then(() => console.log("Copying complete!"))
|
console.error("Error during copy:", err)
|
||||||
.catch((err) => console.error("Error during copy:", err));
|
}
|
||||||
@ -14,7 +14,7 @@ fi
|
|||||||
|
|
||||||
# Trigger the TypeScript build
|
# Trigger the TypeScript build
|
||||||
echo TypeScript build start
|
echo TypeScript build start
|
||||||
npx tsc
|
npm run build:ts
|
||||||
echo TypeScript build finished
|
echo TypeScript build finished
|
||||||
|
|
||||||
# Copy the TypeScript artifacts
|
# Copy the TypeScript artifacts
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
import { dirname, join } from "path";
|
import { dirname, join } from "path";
|
||||||
import swaggerJsdoc from 'swagger-jsdoc';
|
import swaggerJsdoc from "swagger-jsdoc";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -11,28 +11,30 @@ import fs from "fs";
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
definition: {
|
definition: {
|
||||||
openapi: '3.1.1',
|
openapi: "3.1.1",
|
||||||
info: {
|
info: {
|
||||||
title: 'Trilium Notes - Sync server API',
|
title: "Trilium Notes - Sync server API",
|
||||||
version: '0.96.6',
|
version: "0.96.6",
|
||||||
description: "This is the internal sync server API used by Trilium Notes / TriliumNext Notes.\n\n_If you're looking for the officially supported External Trilium API, see [here](https://triliumnext.github.io/Docs/Wiki/etapi.html)._\n\nThis page does not yet list all routes. For a full list, see the [route controller](https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/routes.ts).",
|
description:
|
||||||
contact: {
|
"This is the internal sync server API used by Trilium Notes / TriliumNext Notes.\n\n_If you're looking for the officially supported External Trilium API, see [here](https://triliumnext.github.io/Docs/Wiki/etapi.html)._\n\nThis page does not yet list all routes. For a full list, see the [route controller](https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/routes.ts).",
|
||||||
name: "TriliumNext issue tracker",
|
contact: {
|
||||||
url: "https://github.com/TriliumNext/Notes/issues",
|
name: "TriliumNext issue tracker",
|
||||||
},
|
url: "https://github.com/TriliumNext/Notes/issues"
|
||||||
license: {
|
},
|
||||||
name: "GNU Free Documentation License 1.3 (or later)",
|
license: {
|
||||||
url: "https://www.gnu.org/licenses/fdl-1.3",
|
name: "GNU Free Documentation License 1.3 (or later)",
|
||||||
},
|
url: "https://www.gnu.org/licenses/fdl-1.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
apis: [
|
||||||
apis: [
|
// Put individual files here to have them ordered first.
|
||||||
// Put individual files here to have them ordered first.
|
"./src/routes/api/setup.ts",
|
||||||
'./src/routes/api/setup.ts',
|
// all other files
|
||||||
// all other files
|
"./src/routes/api/*.ts",
|
||||||
'./src/routes/api/*.ts', './bin/generate-openapi.js'
|
"./bin/generate-openapi.js"
|
||||||
],
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const openapiSpecification = swaggerJsdoc(options);
|
const openapiSpecification = swaggerJsdoc(options);
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
if [[ $# -eq 0 ]] ; then
|
if [[ $# -eq 0 ]] ; then
|
||||||
echo "Missing argument of new version"
|
echo "Missing argument of new version"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS "tasks"
|
|
||||||
(
|
|
||||||
"taskId" TEXT NOT NULL PRIMARY KEY,
|
|
||||||
"parentNoteId" TEXT NOT NULL,
|
|
||||||
"title" TEXT NOT NULL DEFAULT "",
|
|
||||||
"dueDate" INTEGER,
|
|
||||||
"isDone" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
"isDeleted" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
"utcDateModified" TEXT NOT NULL
|
|
||||||
);
|
|
||||||
@ -132,14 +132,3 @@ CREATE INDEX IDX_attachments_ownerId_role
|
|||||||
CREATE INDEX IDX_notes_blobId on notes (blobId);
|
CREATE INDEX IDX_notes_blobId on notes (blobId);
|
||||||
CREATE INDEX IDX_revisions_blobId on revisions (blobId);
|
CREATE INDEX IDX_revisions_blobId on revisions (blobId);
|
||||||
CREATE INDEX IDX_attachments_blobId on attachments (blobId);
|
CREATE INDEX IDX_attachments_blobId on attachments (blobId);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS "tasks"
|
|
||||||
(
|
|
||||||
"taskId" TEXT NOT NULL PRIMARY KEY,
|
|
||||||
"parentNoteId" TEXT NOT NULL,
|
|
||||||
"title" TEXT NOT NULL DEFAULT "",
|
|
||||||
"dueDate" INTEGER,
|
|
||||||
"isDone" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
"isDeleted" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
"utcDateModified" TEXT NOT NULL
|
|
||||||
);
|
|
||||||
@ -14,7 +14,7 @@ npm install
|
|||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
See output of `npx esrun dump.ts --help`:
|
See output of `npx tsx dump.ts --help`:
|
||||||
|
|
||||||
```
|
```
|
||||||
dump-db.ts <path_to_document> <target_directory>
|
dump-db.ts <path_to_document> <target_directory>
|
||||||
|
|||||||
858
dump-db/package-lock.json
generated
@ -18,9 +18,9 @@
|
|||||||
"homepage": "https://github.com/TriliumNext/Notes/blob/master/dump-db/README.md",
|
"homepage": "https://github.com/TriliumNext/Notes/blob/master/dump-db/README.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"better-sqlite3": "^11.1.2",
|
"better-sqlite3": "^11.1.2",
|
||||||
"esrun": "^3.2.26",
|
|
||||||
"mime-types": "^2.1.34",
|
"mime-types": "^2.1.34",
|
||||||
"sanitize-filename": "^1.6.3",
|
"sanitize-filename": "^1.6.3",
|
||||||
|
"tsx": "^4.19.3",
|
||||||
"yargs": "^17.3.1"
|
"yargs": "^17.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@ -11,16 +11,14 @@ test("Displays translation on desktop", async ({ page, context }) => {
|
|||||||
const app = new App(page, context);
|
const app = new App(page, context);
|
||||||
await app.goto();
|
await app.goto();
|
||||||
|
|
||||||
await expect(page.locator("#left-pane .quick-search input"))
|
await expect(page.locator("#left-pane .quick-search input")).toHaveAttribute("placeholder", "Quick search");
|
||||||
.toHaveAttribute("placeholder", "Quick search");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Displays translation on mobile", async ({ page, context }) => {
|
test("Displays translation on mobile", async ({ page, context }) => {
|
||||||
const app = new App(page, context);
|
const app = new App(page, context);
|
||||||
await app.goto({ isMobile: true });
|
await app.goto({ isMobile: true });
|
||||||
|
|
||||||
await expect(page.locator("#mobile-sidebar-wrapper .quick-search input"))
|
await expect(page.locator("#mobile-sidebar-wrapper .quick-search input")).toHaveAttribute("placeholder", "Quick search");
|
||||||
.toHaveAttribute("placeholder", "Quick search");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Displays translations in Settings", async ({ page, context }) => {
|
test("Displays translations in Settings", async ({ page, context }) => {
|
||||||
@ -44,14 +42,16 @@ test("User can change language from settings", async ({ page, context }) => {
|
|||||||
|
|
||||||
// Check that the default value (English) is set.
|
// Check that the default value (English) is set.
|
||||||
await expect(app.currentNoteSplit).toContainText("Theme");
|
await expect(app.currentNoteSplit).toContainText("Theme");
|
||||||
const languageCombobox = await app.currentNoteSplit.getByRole("combobox").first();
|
const languageCombobox = app.currentNoteSplit.getByRole("combobox").first();
|
||||||
await expect(languageCombobox).toHaveValue("en");
|
await expect(languageCombobox).toHaveValue("en");
|
||||||
|
|
||||||
// Select Chinese and ensure the translation is set.
|
// Select Chinese and ensure the translation is set.
|
||||||
await languageCombobox.selectOption("cn");
|
await languageCombobox.selectOption("cn");
|
||||||
await expect(app.currentNoteSplit).toContainText("主题", { timeout: 15000 });
|
await expect(app.currentNoteSplit).toContainText("主题", { timeout: 15000 });
|
||||||
|
await expect(languageCombobox).toHaveValue("cn");
|
||||||
|
|
||||||
// Select English again.
|
// Select English again.
|
||||||
await languageCombobox.selectOption("en");
|
await languageCombobox.selectOption("en");
|
||||||
await expect(app.currentNoteSplit).toContainText("Language", { timeout: 15000 });
|
await expect(app.currentNoteSplit).toContainText("Language", { timeout: 15000 });
|
||||||
|
await expect(languageCombobox).toHaveValue("en");
|
||||||
});
|
});
|
||||||
|
|||||||
@ -19,13 +19,13 @@ test("Can drag tabs around", async ({ page, context }) => {
|
|||||||
let tab = app.getTab(0);
|
let tab = app.getTab(0);
|
||||||
|
|
||||||
// Drag the first tab at the end
|
// Drag the first tab at the end
|
||||||
await tab.dragTo(app.getTab(2), { targetPosition: { x: 50, y: 0 }});
|
await tab.dragTo(app.getTab(2), { targetPosition: { x: 50, y: 0 } });
|
||||||
|
|
||||||
tab = app.getTab(2);
|
tab = app.getTab(2);
|
||||||
await expect(tab).toContainText(NOTE_TITLE);
|
await expect(tab).toContainText(NOTE_TITLE);
|
||||||
|
|
||||||
// Drag the tab to the left
|
// Drag the tab to the left
|
||||||
await tab.dragTo(app.getTab(0), { targetPosition: { x: 50, y: 0 }});
|
await tab.dragTo(app.getTab(0), { targetPosition: { x: 50, y: 0 } });
|
||||||
await expect(app.getTab(0)).toContainText(NOTE_TITLE);
|
await expect(app.getTab(0)).toContainText(NOTE_TITLE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,9 @@ test("Displays lint errors for backend script", async ({ page, context }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function expectTooltip(page: Page, tooltip: string) {
|
async function expectTooltip(page: Page, tooltip: string) {
|
||||||
await expect(page.locator(".CodeMirror-lint-tooltip:visible", {
|
await expect(
|
||||||
"hasText": tooltip
|
page.locator(".CodeMirror-lint-tooltip:visible", {
|
||||||
})).toBeVisible();
|
hasText: tooltip
|
||||||
|
})
|
||||||
|
).toBeVisible();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,8 @@ import App from "../support/app";
|
|||||||
|
|
||||||
test("renders ELK flowchart", async ({ page, context }) => {
|
test("renders ELK flowchart", async ({ page, context }) => {
|
||||||
await testAriaSnapshot({
|
await testAriaSnapshot({
|
||||||
page, context,
|
page,
|
||||||
|
context,
|
||||||
noteTitle: "Flowchart ELK on",
|
noteTitle: "Flowchart ELK on",
|
||||||
snapshot: `
|
snapshot: `
|
||||||
- document:
|
- document:
|
||||||
@ -22,12 +23,13 @@ test("renders ELK flowchart", async ({ page, context }) => {
|
|||||||
- paragraph: Guarantee
|
- paragraph: Guarantee
|
||||||
- text: Interfaces for B
|
- text: Interfaces for B
|
||||||
`
|
`
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders standard flowchart", async ({ page, context }) => {
|
test("renders standard flowchart", async ({ page, context }) => {
|
||||||
await testAriaSnapshot({
|
await testAriaSnapshot({
|
||||||
page, context,
|
page,
|
||||||
|
context,
|
||||||
noteTitle: "Flowchart ELK off",
|
noteTitle: "Flowchart ELK off",
|
||||||
snapshot: `
|
snapshot: `
|
||||||
- document:
|
- document:
|
||||||
@ -46,7 +48,7 @@ test("renders standard flowchart", async ({ page, context }) => {
|
|||||||
- paragraph: C
|
- paragraph: C
|
||||||
- text: Interfaces for B
|
- text: Interfaces for B
|
||||||
`
|
`
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
interface AriaTestOpts {
|
interface AriaTestOpts {
|
||||||
|
|||||||
@ -44,8 +44,8 @@ test("Highlights list is displayed", async ({ page, context }) => {
|
|||||||
|
|
||||||
await expect(app.sidebar).toContainText("Highlights List");
|
await expect(app.sidebar).toContainText("Highlights List");
|
||||||
const rootList = app.sidebar.locator(".highlights-list ol");
|
const rootList = app.sidebar.locator(".highlights-list ol");
|
||||||
let index=0;
|
let index = 0;
|
||||||
for (const highlightedEl of [ "Bold 1", "Italic 1", "Underline 1", "Colored text 1", "Background text 1", "Bold 2", "Italic 2", "Underline 2", "Colored text 2", "Background text 2" ]) {
|
for (const highlightedEl of ["Bold 1", "Italic 1", "Underline 1", "Colored text 1", "Background text 1", "Bold 2", "Italic 2", "Underline 2", "Colored text 2", "Background text 2"]) {
|
||||||
await expect(rootList.locator("li").nth(index++)).toContainText(highlightedEl);
|
await expect(rootList.locator("li").nth(index++)).toContainText(highlightedEl);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -54,7 +54,7 @@ test("Displays math popup", async ({ page, context }) => {
|
|||||||
const app = new App(page, context);
|
const app = new App(page, context);
|
||||||
await app.goto();
|
await app.goto();
|
||||||
await app.goToNoteInNewTab("Empty text");
|
await app.goToNoteInNewTab("Empty text");
|
||||||
const noteContent = app.currentNoteSplit.locator(".note-detail-editable-text-editor")
|
const noteContent = app.currentNoteSplit.locator(".note-detail-editable-text-editor");
|
||||||
await noteContent.fill("Hello world");
|
await noteContent.fill("Hello world");
|
||||||
await noteContent.press("ControlOrMeta+M");
|
await noteContent.press("ControlOrMeta+M");
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export default class App {
|
|||||||
this.tabBar = page.locator(".tab-row-widget-container");
|
this.tabBar = page.locator(".tab-row-widget-container");
|
||||||
this.noteTree = page.locator(".tree-wrapper");
|
this.noteTree = page.locator(".tree-wrapper");
|
||||||
this.launcherBar = page.locator("#launcher-container");
|
this.launcherBar = page.locator("#launcher-container");
|
||||||
this.currentNoteSplit = page.locator(".note-split:not(.hidden-ext)")
|
this.currentNoteSplit = page.locator(".note-split:not(.hidden-ext)");
|
||||||
this.sidebar = page.locator("#right-pane");
|
this.sidebar = page.locator("#right-pane");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,12 +42,11 @@ export default class App {
|
|||||||
url = "/";
|
url = "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.page.goto(url, { waitUntil: "networkidle" });
|
await this.page.goto(url, { waitUntil: "networkidle", timeout: 30_000 });
|
||||||
|
|
||||||
// Wait for the page to load.
|
// Wait for the page to load.
|
||||||
if (url === "/") {
|
if (url === "/") {
|
||||||
await expect(this.page.locator(".tree"))
|
await expect(this.page.locator(".tree")).toContainText("Trilium Integration Test");
|
||||||
.toContainText("Trilium Integration Test");
|
|
||||||
await this.closeAllTabs();
|
await this.closeAllTabs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,11 +108,12 @@ export default class App {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(csrfToken).toBeTruthy();
|
expect(csrfToken).toBeTruthy();
|
||||||
await expect(await this.page.request.put(`${BASE_URL}/api/options/${key}/${value}`, {
|
await expect(
|
||||||
headers: {
|
await this.page.request.put(`${BASE_URL}/api/options/${key}/${value}`, {
|
||||||
"x-csrf-token": csrfToken
|
headers: {
|
||||||
}
|
"x-csrf-token": csrfToken
|
||||||
})).toBeOK();
|
}
|
||||||
|
})
|
||||||
|
).toBeOK();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
43
eslint.config.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import eslint from "@eslint/js";
|
||||||
|
import tseslint from "typescript-eslint";
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
// add rule overrides here
|
||||||
|
"no-undef": "off",
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"argsIgnorePattern": "^_",
|
||||||
|
"varsIgnorePattern": "^_",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ignores: [
|
||||||
|
"build/*",
|
||||||
|
"dist/*",
|
||||||
|
"docs/*",
|
||||||
|
"libraries/*",
|
||||||
|
"src/public/app-dist/*",
|
||||||
|
"src/public/app/doc_notes/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
);
|
||||||
28
libraries/codemirror/eslint.js
vendored
@ -35,39 +35,13 @@
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
await glob.requireLibrary(glob.ESLINT);
|
|
||||||
|
|
||||||
if (text.length > 20000) {
|
if (text.length > 20000) {
|
||||||
console.log("Skipping linting because of large size: ", text.length);
|
console.log("Skipping linting because of large size: ", text.length);
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const errors = new eslint().verify(text, {
|
const errors = await glob.linter(text);
|
||||||
root: true,
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: "2019"
|
|
||||||
},
|
|
||||||
extends: ['eslint:recommended', 'airbnb-base'],
|
|
||||||
env: {
|
|
||||||
'browser': true,
|
|
||||||
'node': true
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
'import/no-unresolved': 'off',
|
|
||||||
'func-names': 'off',
|
|
||||||
'comma-dangle': ['warn'],
|
|
||||||
'padded-blocks': 'off',
|
|
||||||
'linebreak-style': 'off',
|
|
||||||
'class-methods-use-this': 'off',
|
|
||||||
'no-unused-vars': ['warn', { vars: 'local', args: 'after-used' }],
|
|
||||||
'no-nested-ternary': 'off',
|
|
||||||
'no-underscore-dangle': ['error', {'allow': ['_super', '_lookupFactory']}]
|
|
||||||
},
|
|
||||||
globals: {
|
|
||||||
"api": "readonly"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(errors);
|
console.log(errors);
|
||||||
|
|
||||||
|
|||||||
112883
libraries/eslint/eslint.js
vendored
1107
package-lock.json
generated
41
package.json
@ -2,7 +2,7 @@
|
|||||||
"name": "trilium",
|
"name": "trilium",
|
||||||
"productName": "TriliumNext Notes",
|
"productName": "TriliumNext Notes",
|
||||||
"description": "Build your personal knowledge base with TriliumNext Notes",
|
"description": "Build your personal knowledge base with TriliumNext Notes",
|
||||||
"version": "0.92.2-beta",
|
"version": "0.92.3-beta",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"main": "./dist/electron-main.js",
|
"main": "./dist/electron-main.js",
|
||||||
"author": {
|
"author": {
|
||||||
@ -43,20 +43,24 @@
|
|||||||
"docs:build-backend": "rimraf ./docs/backend_api && typedoc ./docs/backend_api src/becca/entities/*.ts src/services/backend_script_api.ts src/services/sql.ts",
|
"docs:build-backend": "rimraf ./docs/backend_api && typedoc ./docs/backend_api src/becca/entities/*.ts src/services/backend_script_api.ts src/services/sql.ts",
|
||||||
"docs:build-frontend": "rimraf ./docs/frontend_api && jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/basic_widget.js src/public/app/widgets/note_context_aware_widget.js src/public/app/widgets/right_panel_widget.js",
|
"docs:build-frontend": "rimraf ./docs/frontend_api && jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/basic_widget.js src/public/app/widgets/note_context_aware_widget.js src/public/app/widgets/right_panel_widget.js",
|
||||||
"docs:build": "npm run docs:build-backend && npm run docs:build-frontend",
|
"docs:build": "npm run docs:build-backend && npm run docs:build-frontend",
|
||||||
"build:webpack": "tsx node_modules/webpack/bin/webpack.js -c webpack.config.ts",
|
"build:webpack": "tsx node_modules/webpack/bin/webpack.js -c webpack.config.ts --progress",
|
||||||
"build:prepare-dist": "npm run build:webpack && rimraf ./dist && tsc && tsx ./bin/copy-dist.ts",
|
"build:ts": "tsc -p tsconfig.build.json",
|
||||||
|
"build:clean": "rimraf ./dist ./build",
|
||||||
|
"build:prepare-dist": "npm run build:clean && npm run build:ts && npm run build:webpack && tsx ./bin/copy-dist.ts",
|
||||||
"test": "npm run client:test && npm run server:test",
|
"test": "npm run client:test && npm run server:test",
|
||||||
"server:test": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest",
|
"server:test": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest",
|
||||||
"server:coverage": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest --coverage",
|
"server:coverage": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest --coverage",
|
||||||
"client:test": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest --root src/public/app",
|
"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",
|
"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",
|
"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-edit-db": "cross-env TRILIUM_INTEGRATION_TEST=edit TRILIUM_PORT=8081 TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
|
||||||
"test:integration-mem-db": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
|
"test:integration-mem-db": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
|
||||||
"test:integration-mem-db-dev": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
|
"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:watch-dist": "tsx ./bin/watch-dist.ts",
|
||||||
"dev:prettier-check": "prettier . --check",
|
"dev:prettier-check": "prettier . --check",
|
||||||
"dev:prettier-fix": "prettier . --write",
|
"dev:prettier-fix": "prettier . --write",
|
||||||
|
"dev:linter-check": "eslint .",
|
||||||
|
"dev:linter-fix": "eslint . --fix",
|
||||||
"chore:update-build-info": "tsx bin/update-build-info.ts",
|
"chore:update-build-info": "tsx bin/update-build-info.ts",
|
||||||
"chore:ci-update-nightly-version": "tsx ./bin/update-nightly-version.ts",
|
"chore:ci-update-nightly-version": "tsx ./bin/update-nightly-version.ts",
|
||||||
"chore:generate-document": "cross-env nodemon ./bin/generate_document.ts 1000",
|
"chore:generate-document": "cross-env nodemon ./bin/generate_document.ts 1000",
|
||||||
@ -77,7 +81,7 @@
|
|||||||
"archiver": "7.0.1",
|
"archiver": "7.0.1",
|
||||||
"async-mutex": "0.5.0",
|
"async-mutex": "0.5.0",
|
||||||
"autocomplete.js": "0.38.1",
|
"autocomplete.js": "0.38.1",
|
||||||
"axios": "1.8.1",
|
"axios": "1.8.2",
|
||||||
"better-sqlite3": "11.8.1",
|
"better-sqlite3": "11.8.1",
|
||||||
"boxicons": "2.1.4",
|
"boxicons": "2.1.4",
|
||||||
"chardet": "2.1.0",
|
"chardet": "2.1.0",
|
||||||
@ -98,12 +102,12 @@
|
|||||||
"electron-squirrel-startup": "1.0.1",
|
"electron-squirrel-startup": "1.0.1",
|
||||||
"electron-window-state": "5.0.3",
|
"electron-window-state": "5.0.3",
|
||||||
"escape-html": "1.0.3",
|
"escape-html": "1.0.3",
|
||||||
|
"eslint-linter-browserify": "9.22.0",
|
||||||
"express": "4.21.2",
|
"express": "4.21.2",
|
||||||
"express-rate-limit": "7.5.0",
|
"express-rate-limit": "7.5.0",
|
||||||
"express-session": "1.18.1",
|
"express-session": "1.18.1",
|
||||||
"force-graph": "1.49.2",
|
"force-graph": "1.49.3",
|
||||||
"fs-extra": "11.3.0",
|
"fs-extra": "11.3.0",
|
||||||
"happy-dom": "17.1.8",
|
|
||||||
"helmet": "8.0.0",
|
"helmet": "8.0.0",
|
||||||
"html": "1.0.0",
|
"html": "1.0.0",
|
||||||
"html2plaintext": "2.1.4",
|
"html2plaintext": "2.1.4",
|
||||||
@ -123,7 +127,6 @@
|
|||||||
"jsdom": "26.0.0",
|
"jsdom": "26.0.0",
|
||||||
"jsplumb": "2.15.6",
|
"jsplumb": "2.15.6",
|
||||||
"katex": "0.16.21",
|
"katex": "0.16.21",
|
||||||
"knockout": "3.5.1",
|
|
||||||
"leaflet": "1.9.4",
|
"leaflet": "1.9.4",
|
||||||
"leaflet-gpx": "2.1.2",
|
"leaflet-gpx": "2.1.2",
|
||||||
"mark.js": "8.11.1",
|
"mark.js": "8.11.1",
|
||||||
@ -150,7 +153,6 @@
|
|||||||
"striptags": "3.2.0",
|
"striptags": "3.2.0",
|
||||||
"swagger-ui-express": "5.0.1",
|
"swagger-ui-express": "5.0.1",
|
||||||
"tmp": "0.2.3",
|
"tmp": "0.2.3",
|
||||||
"ts-loader": "9.5.2",
|
|
||||||
"turndown": "7.2.0",
|
"turndown": "7.2.0",
|
||||||
"unescape": "1.0.1",
|
"unescape": "1.0.1",
|
||||||
"vanilla-js-wheel-zoom": "9.0.4",
|
"vanilla-js-wheel-zoom": "9.0.4",
|
||||||
@ -168,7 +170,8 @@
|
|||||||
"@electron-forge/maker-zip": "7.7.0",
|
"@electron-forge/maker-zip": "7.7.0",
|
||||||
"@electron-forge/plugin-auto-unpack-natives": "7.7.0",
|
"@electron-forge/plugin-auto-unpack-natives": "7.7.0",
|
||||||
"@electron/rebuild": "3.7.1",
|
"@electron/rebuild": "3.7.1",
|
||||||
"@playwright/test": "1.50.1",
|
"@eslint/js": "9.22.0",
|
||||||
|
"@playwright/test": "1.51.0",
|
||||||
"@popperjs/core": "2.11.8",
|
"@popperjs/core": "2.11.8",
|
||||||
"@types/archiver": "6.0.3",
|
"@types/archiver": "6.0.3",
|
||||||
"@types/better-sqlite3": "7.6.12",
|
"@types/better-sqlite3": "7.6.12",
|
||||||
@ -193,7 +196,7 @@
|
|||||||
"@types/leaflet-gpx": "1.3.7",
|
"@types/leaflet-gpx": "1.3.7",
|
||||||
"@types/mime-types": "2.1.4",
|
"@types/mime-types": "2.1.4",
|
||||||
"@types/multer": "1.4.12",
|
"@types/multer": "1.4.12",
|
||||||
"@types/node": "22.13.8",
|
"@types/node": "22.13.9",
|
||||||
"@types/react": "18.3.18",
|
"@types/react": "18.3.18",
|
||||||
"@types/react-dom": "18.3.5",
|
"@types/react-dom": "18.3.5",
|
||||||
"@types/safe-compare": "1.1.2",
|
"@types/safe-compare": "1.1.2",
|
||||||
@ -207,23 +210,27 @@
|
|||||||
"@types/swagger-ui-express": "4.1.8",
|
"@types/swagger-ui-express": "4.1.8",
|
||||||
"@types/tmp": "0.2.6",
|
"@types/tmp": "0.2.6",
|
||||||
"@types/turndown": "5.0.5",
|
"@types/turndown": "5.0.5",
|
||||||
"@types/ws": "8.5.14",
|
"@types/ws": "8.18.0",
|
||||||
"@types/xml2js": "0.4.14",
|
"@types/xml2js": "0.4.14",
|
||||||
"@types/yargs": "17.0.33",
|
"@types/yargs": "17.0.33",
|
||||||
"@vitest/coverage-v8": "3.0.7",
|
"@vitest/coverage-v8": "3.0.8",
|
||||||
"autoprefixer": "10.4.20",
|
"autoprefixer": "10.4.20",
|
||||||
"bootstrap": "5.3.3",
|
"bootstrap": "5.3.3",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"css-loader": "7.1.2",
|
"css-loader": "7.1.2",
|
||||||
"electron": "34.3.0",
|
"electron": "34.3.1",
|
||||||
|
"eslint": "9.22.0",
|
||||||
"esm": "3.2.25",
|
"esm": "3.2.25",
|
||||||
|
"globals": "16.0.0",
|
||||||
|
"happy-dom": "17.4.0",
|
||||||
"i18next-http-backend": "3.0.2",
|
"i18next-http-backend": "3.0.2",
|
||||||
"jsdoc": "4.0.4",
|
"jsdoc": "4.0.4",
|
||||||
|
"knockout": "3.5.1",
|
||||||
"lorem-ipsum": "2.0.8",
|
"lorem-ipsum": "2.0.8",
|
||||||
"mini-css-extract-plugin": "2.9.2",
|
"mini-css-extract-plugin": "2.9.2",
|
||||||
"nodemon": "3.1.9",
|
"nodemon": "3.1.9",
|
||||||
"postcss-loader": "8.1.1",
|
"postcss-loader": "8.1.1",
|
||||||
"prettier": "3.5.2",
|
"prettier": "3.5.3",
|
||||||
"rcedit": "4.0.1",
|
"rcedit": "4.0.1",
|
||||||
"rimraf": "6.0.1",
|
"rimraf": "6.0.1",
|
||||||
"sass": "1.85.1",
|
"sass": "1.85.1",
|
||||||
@ -231,11 +238,13 @@
|
|||||||
"split.js": "1.6.5",
|
"split.js": "1.6.5",
|
||||||
"supertest": "7.0.0",
|
"supertest": "7.0.0",
|
||||||
"swagger-jsdoc": "6.2.8",
|
"swagger-jsdoc": "6.2.8",
|
||||||
|
"ts-loader": "9.5.2",
|
||||||
"tslib": "2.8.1",
|
"tslib": "2.8.1",
|
||||||
"tsx": "4.19.3",
|
"tsx": "4.19.3",
|
||||||
"typedoc": "0.27.9",
|
"typedoc": "0.27.9",
|
||||||
"typescript": "5.8.2",
|
"typescript": "5.8.2",
|
||||||
"vitest": "3.0.7",
|
"typescript-eslint": "8.26.0",
|
||||||
|
"vitest": "3.0.8",
|
||||||
"webpack": "5.98.0",
|
"webpack": "5.98.0",
|
||||||
"webpack-cli": "6.0.1",
|
"webpack-cli": "6.0.1",
|
||||||
"webpack-dev-middleware": "7.4.2"
|
"webpack-dev-middleware": "7.4.2"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { defineConfig, devices } from '@playwright/test';
|
import { defineConfig, devices } from "@playwright/test";
|
||||||
|
|
||||||
const SERVER_URL = 'http://127.0.0.1:8082';
|
const SERVER_URL = "http://127.0.0.1:8082";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read environment variables from file.
|
* Read environment variables from file.
|
||||||
@ -14,68 +14,70 @@ const SERVER_URL = 'http://127.0.0.1:8082';
|
|||||||
* See https://playwright.dev/docs/test-configuration.
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
*/
|
*/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
testDir: './e2e',
|
testDir: "./e2e",
|
||||||
/* Run tests in files in parallel */
|
/* Run tests in files in parallel */
|
||||||
fullyParallel: true,
|
fullyParallel: true,
|
||||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
forbidOnly: !!process.env.CI,
|
forbidOnly: !!process.env.CI,
|
||||||
/* Retry on CI only */
|
/* Retry on CI only */
|
||||||
retries: process.env.CI ? 2 : 0,
|
retries: process.env.CI ? 2 : 0,
|
||||||
/* Opt out of parallel tests on CI. */
|
/* Opt out of parallel tests on CI. */
|
||||||
workers: process.env.CI ? 1 : undefined,
|
workers: process.env.CI ? 1 : undefined,
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: 'html',
|
reporter: "html",
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
use: {
|
use: {
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
baseURL: SERVER_URL,
|
baseURL: SERVER_URL,
|
||||||
|
|
||||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
trace: 'on-first-retry',
|
trace: "on-first-retry"
|
||||||
},
|
|
||||||
|
|
||||||
/* Configure projects for major browsers */
|
|
||||||
projects: [
|
|
||||||
{
|
|
||||||
name: 'chromium',
|
|
||||||
use: { ...devices['Desktop Chrome'] },
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// {
|
/* Configure projects for major browsers */
|
||||||
// name: 'firefox',
|
projects: [
|
||||||
// use: { ...devices['Desktop Firefox'] },
|
{
|
||||||
// },
|
name: "chromium",
|
||||||
|
use: { ...devices["Desktop Chrome"] }
|
||||||
|
}
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// name: 'webkit',
|
// name: 'firefox',
|
||||||
// use: { ...devices['Desktop Safari'] },
|
// use: { ...devices['Desktop Firefox'] },
|
||||||
// },
|
// },
|
||||||
|
|
||||||
/* Test against mobile viewports. */
|
// {
|
||||||
// {
|
// name: 'webkit',
|
||||||
// name: 'Mobile Chrome',
|
// use: { ...devices['Desktop Safari'] },
|
||||||
// use: { ...devices['Pixel 5'] },
|
// },
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'Mobile Safari',
|
|
||||||
// use: { ...devices['iPhone 12'] },
|
|
||||||
// },
|
|
||||||
|
|
||||||
/* Test against branded browsers. */
|
/* Test against mobile viewports. */
|
||||||
// {
|
// {
|
||||||
// name: 'Microsoft Edge',
|
// name: 'Mobile Chrome',
|
||||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
// use: { ...devices['Pixel 5'] },
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// name: 'Google Chrome',
|
// name: 'Mobile Safari',
|
||||||
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
// use: { ...devices['iPhone 12'] },
|
||||||
// },
|
// },
|
||||||
],
|
|
||||||
|
|
||||||
/* Run your local dev server before starting the tests */
|
/* Test against branded browsers. */
|
||||||
webServer: !process.env.TRILIUM_DOCKER ? {
|
// {
|
||||||
command: 'npm run test:integration-mem-db-dev',
|
// name: 'Microsoft Edge',
|
||||||
url: SERVER_URL,
|
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||||
reuseExistingServer: !process.env.CI,
|
// },
|
||||||
} : undefined,
|
// {
|
||||||
|
// name: 'Google Chrome',
|
||||||
|
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
|
||||||
|
/* Run your local dev server before starting the tests */
|
||||||
|
webServer: !process.env.TRILIUM_DOCKER
|
||||||
|
? {
|
||||||
|
command: "npm run test:integration-mem-db-dev",
|
||||||
|
url: SERVER_URL,
|
||||||
|
reuseExistingServer: !process.env.CI
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,4 +6,4 @@ etapi.describeEtapi("app_info", () => {
|
|||||||
expect(appInfo.clipperProtocolVersion).toEqual("1.0");
|
expect(appInfo.clipperProtocolVersion).toEqual("1.0");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -7,4 +7,4 @@ etapi.describeEtapi("backup", () => {
|
|||||||
expect(response.status).toEqual(204);
|
expect(response.status).toEqual(204);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -23,4 +23,4 @@ etapi.describeEtapi("import", () => {
|
|||||||
expect(content).toContain("test export content");
|
expect(content).toContain("test export content");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -100,4 +100,4 @@ etapi.describeEtapi("notes", () => {
|
|||||||
expect(error.message).toEqual(`Note '${note.noteId}' not found.`);
|
expect(error.message).toEqual(`Note '${note.noteId}' not found.`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import type { AttachmentRow, BlobRow, RevisionRow } from "./entities/rows.js";
|
|||||||
import BBlob from "./entities/bblob.js";
|
import BBlob from "./entities/bblob.js";
|
||||||
import BRecentNote from "./entities/brecent_note.js";
|
import BRecentNote from "./entities/brecent_note.js";
|
||||||
import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js";
|
import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js";
|
||||||
import type BTask from "./entities/btask.js";
|
|
||||||
|
|
||||||
interface AttachmentOpts {
|
interface AttachmentOpts {
|
||||||
includeContentLength?: boolean;
|
includeContentLength?: boolean;
|
||||||
@ -33,7 +32,6 @@ export default class Becca {
|
|||||||
attributeIndex!: Record<string, BAttribute[]>;
|
attributeIndex!: Record<string, BAttribute[]>;
|
||||||
options!: Record<string, BOption>;
|
options!: Record<string, BOption>;
|
||||||
etapiTokens!: Record<string, BEtapiToken>;
|
etapiTokens!: Record<string, BEtapiToken>;
|
||||||
tasks!: Record<string, BTask>;
|
|
||||||
|
|
||||||
allNoteSetCache: NoteSet | null;
|
allNoteSetCache: NoteSet | null;
|
||||||
|
|
||||||
@ -50,7 +48,6 @@ export default class Becca {
|
|||||||
this.attributeIndex = {};
|
this.attributeIndex = {};
|
||||||
this.options = {};
|
this.options = {};
|
||||||
this.etapiTokens = {};
|
this.etapiTokens = {};
|
||||||
this.tasks = {};
|
|
||||||
|
|
||||||
this.dirtyNoteSetCache();
|
this.dirtyNoteSetCache();
|
||||||
|
|
||||||
@ -216,14 +213,6 @@ export default class Becca {
|
|||||||
return this.etapiTokens[etapiTokenId];
|
return this.etapiTokens[etapiTokenId];
|
||||||
}
|
}
|
||||||
|
|
||||||
getTasks(): BTask[] {
|
|
||||||
return Object.values(this.tasks);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTask(taskId: string): BTask | null {
|
|
||||||
return this.tasks[taskId];
|
|
||||||
}
|
|
||||||
|
|
||||||
getEntity<T extends AbstractBeccaEntity<T>>(entityName: string, entityId: string): AbstractBeccaEntity<T> | null {
|
getEntity<T extends AbstractBeccaEntity<T>>(entityName: string, entityId: string): AbstractBeccaEntity<T> | null {
|
||||||
if (!entityName || !entityId) {
|
if (!entityName || !entityId) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -11,10 +11,9 @@ import BOption from "./entities/boption.js";
|
|||||||
import BEtapiToken from "./entities/betapi_token.js";
|
import BEtapiToken from "./entities/betapi_token.js";
|
||||||
import cls from "../services/cls.js";
|
import cls from "../services/cls.js";
|
||||||
import entityConstructor from "../becca/entity_constructor.js";
|
import entityConstructor from "../becca/entity_constructor.js";
|
||||||
import type { AttributeRow, BranchRow, EtapiTokenRow, NoteRow, OptionRow, TaskRow } from "./entities/rows.js";
|
import type { AttributeRow, BranchRow, EtapiTokenRow, NoteRow, OptionRow } from "./entities/rows.js";
|
||||||
import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js";
|
import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js";
|
||||||
import ws from "../services/ws.js";
|
import ws from "../services/ws.js";
|
||||||
import BTask from "./entities/btask.js";
|
|
||||||
|
|
||||||
const beccaLoaded = new Promise<void>(async (res, rej) => {
|
const beccaLoaded = new Promise<void>(async (res, rej) => {
|
||||||
const sqlInit = (await import("../services/sql_init.js")).default;
|
const sqlInit = (await import("../services/sql_init.js")).default;
|
||||||
@ -64,17 +63,6 @@ function load() {
|
|||||||
for (const row of sql.getRows<EtapiTokenRow>(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) {
|
for (const row of sql.getRows<EtapiTokenRow>(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) {
|
||||||
new BEtapiToken(row);
|
new BEtapiToken(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
for (const row of sql.getRows<TaskRow>(`SELECT taskId, parentNoteId, title, dueDate, isDone, isDeleted FROM tasks WHERE isDeleted = 0`)) {
|
|
||||||
new BTask(row);
|
|
||||||
}
|
|
||||||
} catch (e: any) {
|
|
||||||
// Some older migrations trigger becca which would fail since the "tasks" table is not yet defined (didn't reach the right migration).
|
|
||||||
if (!(e.message.includes("no such table"))) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const noteId in becca.notes) {
|
for (const noteId in becca.notes) {
|
||||||
|
|||||||
@ -1618,7 +1618,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
|||||||
* @param matchBy - choose by which property we detect if to update an existing attachment.
|
* @param matchBy - choose by which property we detect if to update an existing attachment.
|
||||||
* Supported values are either 'attachmentId' (default) or 'title'
|
* Supported values are either 'attachmentId' (default) or 'title'
|
||||||
*/
|
*/
|
||||||
saveAttachment({ attachmentId, role, mime, title, content, position }: AttachmentRow, matchBy = "attachmentId") {
|
saveAttachment({ attachmentId, role, mime, title, content, position }: AttachmentRow, matchBy: "attachmentId" | "title" | undefined = "attachmentId") {
|
||||||
if (!["attachmentId", "title"].includes(matchBy)) {
|
if (!["attachmentId", "title"].includes(matchBy)) {
|
||||||
throw new Error(`Unsupported value '${matchBy}' for matchBy param, has to be either 'attachmentId' or 'title'.`);
|
throw new Error(`Unsupported value '${matchBy}' for matchBy param, has to be either 'attachmentId' or 'title'.`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import becca from "../becca.js";
|
|||||||
import AbstractBeccaEntity from "./abstract_becca_entity.js";
|
import AbstractBeccaEntity from "./abstract_becca_entity.js";
|
||||||
import sql from "../../services/sql.js";
|
import sql from "../../services/sql.js";
|
||||||
import BAttachment from "./battachment.js";
|
import BAttachment from "./battachment.js";
|
||||||
import type { AttachmentRow, RevisionRow } from "./rows.js";
|
import type { AttachmentRow, NoteType, RevisionRow } from "./rows.js";
|
||||||
import eraseService from "../../services/erase.js";
|
import eraseService from "../../services/erase.js";
|
||||||
|
|
||||||
interface ContentOpts {
|
interface ContentOpts {
|
||||||
@ -36,7 +36,7 @@ class BRevision extends AbstractBeccaEntity<BRevision> {
|
|||||||
|
|
||||||
revisionId?: string;
|
revisionId?: string;
|
||||||
noteId!: string;
|
noteId!: string;
|
||||||
type!: string;
|
type!: NoteType;
|
||||||
mime!: string;
|
mime!: string;
|
||||||
title!: string;
|
title!: string;
|
||||||
dateLastEdited?: string;
|
dateLastEdited?: string;
|
||||||
|
|||||||
@ -1,84 +0,0 @@
|
|||||||
import date_utils from "../../services/date_utils.js";
|
|
||||||
import AbstractBeccaEntity from "./abstract_becca_entity.js";
|
|
||||||
import type BOption from "./boption.js";
|
|
||||||
import type { TaskRow } from "./rows.js";
|
|
||||||
|
|
||||||
export default class BTask extends AbstractBeccaEntity<BOption> {
|
|
||||||
|
|
||||||
static get entityName() {
|
|
||||||
return "tasks";
|
|
||||||
}
|
|
||||||
|
|
||||||
static get primaryKeyName() {
|
|
||||||
return "taskId";
|
|
||||||
}
|
|
||||||
|
|
||||||
static get hashedProperties() {
|
|
||||||
return [ "taskId", "parentNoteId", "title", "dueDate", "isDone", "isDeleted" ];
|
|
||||||
}
|
|
||||||
|
|
||||||
taskId?: string;
|
|
||||||
parentNoteId!: string;
|
|
||||||
title!: string;
|
|
||||||
dueDate?: string;
|
|
||||||
isDone!: boolean;
|
|
||||||
private _isDeleted?: boolean;
|
|
||||||
|
|
||||||
constructor(row?: TaskRow) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (!row) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateFromRow(row);
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
get isDeleted() {
|
|
||||||
return !!this._isDeleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateFromRow(row: TaskRow) {
|
|
||||||
this.taskId = row.taskId;
|
|
||||||
this.parentNoteId = row.parentNoteId;
|
|
||||||
this.title = row.title;
|
|
||||||
this.dueDate = row.dueDate;
|
|
||||||
this.isDone = !!row.isDone;
|
|
||||||
this._isDeleted = !!row.isDeleted;
|
|
||||||
this.utcDateModified = row.utcDateModified;
|
|
||||||
|
|
||||||
if (this.taskId) {
|
|
||||||
this.becca.tasks[this.taskId] = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if (this.taskId) {
|
|
||||||
this.becca.tasks[this.taskId] = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected beforeSaving(opts?: {}): void {
|
|
||||||
super.beforeSaving();
|
|
||||||
|
|
||||||
this.utcDateModified = date_utils.utcNowDateTime();
|
|
||||||
|
|
||||||
if (this.taskId) {
|
|
||||||
this.becca.tasks[this.taskId] = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getPojo() {
|
|
||||||
return {
|
|
||||||
taskId: this.taskId,
|
|
||||||
parentNoteId: this.parentNoteId,
|
|
||||||
title: this.title,
|
|
||||||
dueDate: this.dueDate,
|
|
||||||
isDone: this.isDone,
|
|
||||||
isDeleted: this.isDeleted,
|
|
||||||
utcDateModified: this.utcDateModified
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -22,7 +22,7 @@ export interface AttachmentRow {
|
|||||||
export interface RevisionRow {
|
export interface RevisionRow {
|
||||||
revisionId?: string;
|
revisionId?: string;
|
||||||
noteId: string;
|
noteId: string;
|
||||||
type: string;
|
type: NoteType;
|
||||||
mime: string;
|
mime: string;
|
||||||
isProtected?: boolean;
|
isProtected?: boolean;
|
||||||
title: string;
|
title: string;
|
||||||
@ -139,13 +139,3 @@ export interface NoteRow {
|
|||||||
utcDateModified: string;
|
utcDateModified: string;
|
||||||
content?: string | Buffer;
|
content?: string | Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TaskRow {
|
|
||||||
taskId?: string;
|
|
||||||
parentNoteId: string;
|
|
||||||
title: string;
|
|
||||||
dueDate?: string;
|
|
||||||
isDone?: boolean;
|
|
||||||
isDeleted?: boolean;
|
|
||||||
utcDateModified?: string;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import BNote from "./entities/bnote.js";
|
|||||||
import BOption from "./entities/boption.js";
|
import BOption from "./entities/boption.js";
|
||||||
import BRecentNote from "./entities/brecent_note.js";
|
import BRecentNote from "./entities/brecent_note.js";
|
||||||
import BRevision from "./entities/brevision.js";
|
import BRevision from "./entities/brevision.js";
|
||||||
import BTask from "./entities/btask.js";
|
|
||||||
|
|
||||||
type EntityClass = new (row?: any) => AbstractBeccaEntity<any>;
|
type EntityClass = new (row?: any) => AbstractBeccaEntity<any>;
|
||||||
|
|
||||||
@ -22,8 +21,7 @@ const ENTITY_NAME_TO_ENTITY: Record<string, ConstructorData<any> & EntityClass>
|
|||||||
notes: BNote,
|
notes: BNote,
|
||||||
options: BOption,
|
options: BOption,
|
||||||
recent_notes: BRecentNote,
|
recent_notes: BRecentNote,
|
||||||
revisions: BRevision,
|
revisions: BRevision
|
||||||
tasks: BTask
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function getEntityFromEntityName(entityName: keyof typeof ENTITY_NAME_TO_ENTITY) {
|
function getEntityFromEntityName(entityName: keyof typeof ENTITY_NAME_TO_ENTITY) {
|
||||||
|
|||||||
12
src/errors/forbidden_error.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import HttpError from "./http_error.js";
|
||||||
|
|
||||||
|
class ForbiddenError extends HttpError {
|
||||||
|
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message, 403);
|
||||||
|
this.name = "ForbiddenError";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ForbiddenError;
|
||||||
13
src/errors/http_error.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
class HttpError extends Error {
|
||||||
|
|
||||||
|
statusCode: number;
|
||||||
|
|
||||||
|
constructor(message: string, statusCode: number) {
|
||||||
|
super(message);
|
||||||
|
this.name = "HttpError";
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HttpError;
|
||||||
@ -1,9 +1,12 @@
|
|||||||
class NotFoundError {
|
import HttpError from "./http_error.js";
|
||||||
message: string;
|
|
||||||
|
class NotFoundError extends HttpError {
|
||||||
|
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
this.message = message;
|
super(message, 404);
|
||||||
|
this.name = "NotFoundError";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NotFoundError;
|
export default NotFoundError;
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
class ValidationError {
|
import HttpError from "./http_error.js";
|
||||||
message: string;
|
|
||||||
|
class ValidationError extends HttpError {
|
||||||
|
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
this.message = message;
|
super(message, 400)
|
||||||
|
this.name = "ValidationError";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ValidationError;
|
export default ValidationError;
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import type NoteTreeWidget from "../widgets/note_tree.js";
|
|||||||
import type { default as NoteContext, GetTextEditorCallback } from "./note_context.js";
|
import type { default as NoteContext, GetTextEditorCallback } from "./note_context.js";
|
||||||
import type { ContextMenuEvent } from "../menus/context_menu.js";
|
import type { ContextMenuEvent } from "../menus/context_menu.js";
|
||||||
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
|
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
|
||||||
|
import type EditableTextTypeWidget from "../widgets/type_widgets/editable_text.js";
|
||||||
|
|
||||||
interface Layout {
|
interface Layout {
|
||||||
getRootWidget: (appContext: AppContext) => RootWidget;
|
getRootWidget: (appContext: AppContext) => RootWidget;
|
||||||
@ -62,7 +63,7 @@ export interface NoteCommandData extends CommandData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ExecuteCommandData<T> extends CommandData {
|
export interface ExecuteCommandData<T> extends CommandData {
|
||||||
resolve: (data: T) => void
|
resolve: (data: T) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,7 +71,7 @@ export interface ExecuteCommandData<T> extends CommandData {
|
|||||||
*/
|
*/
|
||||||
export type CommandMappings = {
|
export type CommandMappings = {
|
||||||
"api-log-messages": CommandData;
|
"api-log-messages": CommandData;
|
||||||
focusTree: CommandData,
|
focusTree: CommandData;
|
||||||
focusOnTitle: CommandData;
|
focusOnTitle: CommandData;
|
||||||
focusOnDetail: CommandData;
|
focusOnDetail: CommandData;
|
||||||
focusOnSearchDefinition: Required<CommandData>;
|
focusOnSearchDefinition: Required<CommandData>;
|
||||||
@ -108,7 +109,7 @@ export type CommandMappings = {
|
|||||||
showInfoDialog: ConfirmWithMessageOptions;
|
showInfoDialog: ConfirmWithMessageOptions;
|
||||||
showConfirmDialog: ConfirmWithMessageOptions;
|
showConfirmDialog: ConfirmWithMessageOptions;
|
||||||
showRecentChanges: CommandData & { ancestorNoteId: string };
|
showRecentChanges: CommandData & { ancestorNoteId: string };
|
||||||
showImportDialog: CommandData & { noteId: string; };
|
showImportDialog: CommandData & { noteId: string };
|
||||||
openNewNoteSplit: NoteCommandData;
|
openNewNoteSplit: NoteCommandData;
|
||||||
openInWindow: NoteCommandData;
|
openInWindow: NoteCommandData;
|
||||||
openNoteInNewTab: CommandData;
|
openNoteInNewTab: CommandData;
|
||||||
@ -131,8 +132,10 @@ export type CommandMappings = {
|
|||||||
editNoteTitle: ContextMenuCommandData;
|
editNoteTitle: ContextMenuCommandData;
|
||||||
protectSubtree: ContextMenuCommandData;
|
protectSubtree: ContextMenuCommandData;
|
||||||
unprotectSubtree: ContextMenuCommandData;
|
unprotectSubtree: ContextMenuCommandData;
|
||||||
openBulkActionsDialog: ContextMenuCommandData | {
|
openBulkActionsDialog:
|
||||||
selectedOrActiveNoteIds?: string[]
|
| ContextMenuCommandData
|
||||||
|
| {
|
||||||
|
selectedOrActiveNoteIds?: string[];
|
||||||
};
|
};
|
||||||
editBranchPrefix: ContextMenuCommandData;
|
editBranchPrefix: ContextMenuCommandData;
|
||||||
convertNoteToAttachment: ContextMenuCommandData;
|
convertNoteToAttachment: ContextMenuCommandData;
|
||||||
@ -221,11 +224,11 @@ export type CommandMappings = {
|
|||||||
moveTabToNewWindow: CommandData;
|
moveTabToNewWindow: CommandData;
|
||||||
copyTabToNewWindow: CommandData;
|
copyTabToNewWindow: CommandData;
|
||||||
closeActiveTab: CommandData & {
|
closeActiveTab: CommandData & {
|
||||||
$el: JQuery<HTMLElement>
|
$el: JQuery<HTMLElement>;
|
||||||
},
|
};
|
||||||
setZoomFactorAndSave: {
|
setZoomFactorAndSave: {
|
||||||
zoomFactor: string;
|
zoomFactor: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
reEvaluateRightPaneVisibility: CommandData;
|
reEvaluateRightPaneVisibility: CommandData;
|
||||||
runActiveNote: CommandData;
|
runActiveNote: CommandData;
|
||||||
@ -234,18 +237,18 @@ export type CommandMappings = {
|
|||||||
};
|
};
|
||||||
scrollToEnd: CommandData;
|
scrollToEnd: CommandData;
|
||||||
closeThisNoteSplit: CommandData;
|
closeThisNoteSplit: CommandData;
|
||||||
moveThisNoteSplit: CommandData & { isMovingLeft: boolean; };
|
moveThisNoteSplit: CommandData & { isMovingLeft: boolean };
|
||||||
|
|
||||||
// Geomap
|
// Geomap
|
||||||
deleteFromMap: { noteId: string },
|
deleteFromMap: { noteId: string };
|
||||||
openGeoLocation: { noteId: string, event: JQuery.MouseDownEvent }
|
openGeoLocation: { noteId: string; event: JQuery.MouseDownEvent };
|
||||||
|
|
||||||
toggleZenMode: CommandData;
|
toggleZenMode: CommandData;
|
||||||
|
|
||||||
updateAttributeList: CommandData & { attributes: Attribute[] };
|
updateAttributeList: CommandData & { attributes: Attribute[] };
|
||||||
saveAttributes: CommandData;
|
saveAttributes: CommandData;
|
||||||
reloadAttributes: CommandData;
|
reloadAttributes: CommandData;
|
||||||
refreshNoteList: CommandData & { noteId: string; };
|
refreshNoteList: CommandData & { noteId: string };
|
||||||
|
|
||||||
refreshResults: {};
|
refreshResults: {};
|
||||||
refreshSearchDefinition: {};
|
refreshSearchDefinition: {};
|
||||||
@ -348,7 +351,7 @@ type EventMappings = {
|
|||||||
ntxId: string | null | undefined; // TODO: deduplicate ntxId
|
ntxId: string | null | undefined; // TODO: deduplicate ntxId
|
||||||
};
|
};
|
||||||
tabReorder: {
|
tabReorder: {
|
||||||
ntxIdsInOrder: string[]
|
ntxIdsInOrder: string[];
|
||||||
};
|
};
|
||||||
refreshNoteList: {
|
refreshNoteList: {
|
||||||
noteId: string;
|
noteId: string;
|
||||||
@ -359,6 +362,12 @@ type EventMappings = {
|
|||||||
relationMapResetPanZoom: { ntxId: string | null | undefined };
|
relationMapResetPanZoom: { ntxId: string | null | undefined };
|
||||||
relationMapResetZoomIn: { ntxId: string | null | undefined };
|
relationMapResetZoomIn: { ntxId: string | null | undefined };
|
||||||
relationMapResetZoomOut: { ntxId: string | null | undefined };
|
relationMapResetZoomOut: { ntxId: string | null | undefined };
|
||||||
|
activeNoteChangedEvent: {};
|
||||||
|
showAddLinkDialog: {
|
||||||
|
textTypeWidget: EditableTextTypeWidget;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EventListener<T extends EventNames> = {
|
export type EventListener<T extends EventNames> = {
|
||||||
@ -542,10 +551,12 @@ $(window).on("beforeunload", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$(window).on("hashchange", function () {
|
$(window).on("hashchange", function () {
|
||||||
const { notePath, ntxId, viewScope } = linkService.parseNavigationStateFromUrl(window.location.href);
|
const { notePath, ntxId, viewScope, searchString } = linkService.parseNavigationStateFromUrl(window.location.href);
|
||||||
|
|
||||||
if (notePath || ntxId) {
|
if (notePath || ntxId) {
|
||||||
appContext.tabManager.switchToNoteContext(ntxId, notePath, viewScope);
|
appContext.tabManager.switchToNoteContext(ntxId, notePath, viewScope);
|
||||||
|
} else if (searchString) {
|
||||||
|
appContext.triggerCommand("searchNotes", { searchString });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
|
|||||||
children: ChildT[];
|
children: ChildT[];
|
||||||
initialized: Promise<void> | null;
|
initialized: Promise<void> | null;
|
||||||
parent?: TypedComponent<any>;
|
parent?: TypedComponent<any>;
|
||||||
position!: number;
|
_position!: number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.componentId = `${this.sanitizedClassName}-${utils.randomString(8)}`;
|
this.componentId = `${this.sanitizedClassName}-${utils.randomString(8)}`;
|
||||||
@ -31,6 +31,14 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
|
|||||||
return this.constructor.name.replace(/[^A-Z0-9]/gi, "_");
|
return this.constructor.name.replace(/[^A-Z0-9]/gi, "_");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get position() {
|
||||||
|
return this._position;
|
||||||
|
}
|
||||||
|
|
||||||
|
set position(newPosition: number) {
|
||||||
|
this._position = newPosition;
|
||||||
|
}
|
||||||
|
|
||||||
setParent(parent: TypedComponent<any>) {
|
setParent(parent: TypedComponent<any>) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@ -369,7 +369,8 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
|||||||
|
|
||||||
const { note, viewScope } = this;
|
const { note, viewScope } = this;
|
||||||
|
|
||||||
let title = viewScope?.viewMode === "default" ? note.title : `${note.title}: ${viewScope?.viewMode}`;
|
const isNormalView = (viewScope?.viewMode === "default" || viewScope?.viewMode === "contextual-help");
|
||||||
|
let title = (isNormalView ? note.title : `${note.title}: ${viewScope?.viewMode}`);
|
||||||
|
|
||||||
if (viewScope?.attachmentId) {
|
if (viewScope?.attachmentId) {
|
||||||
// assuming the attachment has been already loaded
|
// assuming the attachment has been already loaded
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export default class ShortcutComponent extends Component implements EventListene
|
|||||||
}
|
}
|
||||||
|
|
||||||
bindNoteShortcutHandler(labelOrRow: AttributeRow) {
|
bindNoteShortcutHandler(labelOrRow: AttributeRow) {
|
||||||
const handler = () => appContext.tabManager.getActiveContext().setNote(labelOrRow.noteId);
|
const handler = () => appContext.tabManager.getActiveContext()?.setNote(labelOrRow.noteId);
|
||||||
const namespace = labelOrRow.attributeId;
|
const namespace = labelOrRow.attributeId;
|
||||||
|
|
||||||
if (labelOrRow.isDeleted) {
|
if (labelOrRow.isDeleted) {
|
||||||
|
|||||||
@ -248,7 +248,7 @@ export default class TabManager extends Component {
|
|||||||
await noteContext.setEmpty();
|
await noteContext.setEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
async openEmptyTab(ntxId = null, hoistedNoteId = "root", mainNtxId = null) {
|
async openEmptyTab(ntxId = null, hoistedNoteId = "root", mainNtxId) {
|
||||||
const noteContext = new NoteContext(ntxId, hoistedNoteId, mainNtxId);
|
const noteContext = new NoteContext(ntxId, hoistedNoteId, mainNtxId);
|
||||||
|
|
||||||
const existingNoteContext = this.children.find((nc) => nc.ntxId === noteContext.ntxId);
|
const existingNoteContext = this.children.find((nc) => nc.ntxId === noteContext.ntxId);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"formatVersion": 2,
|
"formatVersion": 2,
|
||||||
"appVersion": "0.92.0-beta",
|
"appVersion": "0.92.2-beta",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"isClone": false,
|
"isClone": false,
|
||||||
@ -34,7 +34,7 @@
|
|||||||
"OkOZllzB3fqN",
|
"OkOZllzB3fqN",
|
||||||
"yoAe4jV2yzbd"
|
"yoAe4jV2yzbd"
|
||||||
],
|
],
|
||||||
"title": "Features",
|
"title": "New Features",
|
||||||
"notePosition": 40,
|
"notePosition": 40,
|
||||||
"prefix": null,
|
"prefix": null,
|
||||||
"isExpanded": false,
|
"isExpanded": false,
|
||||||
@ -47,53 +47,91 @@
|
|||||||
"value": "bx bx-star",
|
"value": "bx bx-star",
|
||||||
"isInheritable": false,
|
"isInheritable": false,
|
||||||
"position": 10
|
"position": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "sorted",
|
||||||
|
"value": "dateCreated",
|
||||||
|
"isInheritable": false,
|
||||||
|
"position": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "sortDirection",
|
||||||
|
"value": "desc",
|
||||||
|
"isInheritable": false,
|
||||||
|
"position": 30
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"format": "html",
|
"format": "html",
|
||||||
"attachments": [],
|
"attachments": [],
|
||||||
"dirFileName": "Features",
|
"dirFileName": "New Features",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"isClone": false,
|
"isClone": false,
|
||||||
"noteId": "13D1lOc9sqmZ",
|
"noteId": "3I277VKYxWDH",
|
||||||
"notePath": [
|
"notePath": [
|
||||||
"OkOZllzB3fqN",
|
"OkOZllzB3fqN",
|
||||||
"yoAe4jV2yzbd",
|
"yoAe4jV2yzbd",
|
||||||
"13D1lOc9sqmZ"
|
"3I277VKYxWDH"
|
||||||
],
|
],
|
||||||
"title": "Export as PDF",
|
"title": "Right-to-left text notes",
|
||||||
"notePosition": 20,
|
"notePosition": 10,
|
||||||
"prefix": null,
|
"prefix": null,
|
||||||
"isExpanded": false,
|
"isExpanded": false,
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"mime": "text/html",
|
"mime": "text/html",
|
||||||
"attributes": [],
|
"attributes": [
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "iconClass",
|
||||||
|
"value": "bx bx-align-right",
|
||||||
|
"isInheritable": false,
|
||||||
|
"position": 10
|
||||||
|
}
|
||||||
|
],
|
||||||
"format": "html",
|
"format": "html",
|
||||||
"dataFileName": "Export as PDF.html",
|
"dataFileName": "Right-to-left text notes.html",
|
||||||
"attachments": [
|
"attachments": [
|
||||||
{
|
{
|
||||||
"attachmentId": "xsGM34t8ssKV",
|
"attachmentId": "PSBNAvDyj5Vy",
|
||||||
"title": "image.png",
|
"title": "image.png",
|
||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "Export as PDF_image.png"
|
"dataFileName": "Right-to-left text notes_i.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "cvyes4f1Vhmm",
|
"attachmentId": "YXYIJznak915",
|
||||||
"title": "image.png",
|
"title": "image.png",
|
||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "1_Export as PDF_image.png"
|
"dataFileName": "1_Right-to-left text notes_i.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "b3v1pLE6TF1Y",
|
"attachmentId": "Do0S17lDl7uu",
|
||||||
"title": "image.png",
|
"title": "image.png",
|
||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "2_Export as PDF_image.png"
|
"dataFileName": "2_Right-to-left text notes_i.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attachmentId": "D3lyhPvPvocb",
|
||||||
|
"title": "image.png",
|
||||||
|
"role": "image",
|
||||||
|
"mime": "image/png",
|
||||||
|
"position": 10,
|
||||||
|
"dataFileName": "3_Right-to-left text notes_i.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attachmentId": "Tu7llk3GgRkA",
|
||||||
|
"title": "image.png",
|
||||||
|
"role": "image",
|
||||||
|
"mime": "image/png",
|
||||||
|
"position": 10,
|
||||||
|
"dataFileName": "4_Right-to-left text notes_i.png"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -106,12 +144,20 @@
|
|||||||
"B3YLYM4erjnW"
|
"B3YLYM4erjnW"
|
||||||
],
|
],
|
||||||
"title": "Zen mode",
|
"title": "Zen mode",
|
||||||
"notePosition": 30,
|
"notePosition": 20,
|
||||||
"prefix": null,
|
"prefix": null,
|
||||||
"isExpanded": false,
|
"isExpanded": false,
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"mime": "text/html",
|
"mime": "text/html",
|
||||||
"attributes": [],
|
"attributes": [
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "iconClass",
|
||||||
|
"value": "bx bxs-yin-yang",
|
||||||
|
"isInheritable": false,
|
||||||
|
"position": 10
|
||||||
|
}
|
||||||
|
],
|
||||||
"format": "html",
|
"format": "html",
|
||||||
"dataFileName": "Zen mode.html",
|
"dataFileName": "Zen mode.html",
|
||||||
"attachments": [
|
"attachments": [
|
||||||
@ -180,6 +226,50 @@
|
|||||||
"dataFileName": "7_Zen mode_image.png"
|
"dataFileName": "7_Zen mode_image.png"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isClone": false,
|
||||||
|
"noteId": "13D1lOc9sqmZ",
|
||||||
|
"notePath": [
|
||||||
|
"OkOZllzB3fqN",
|
||||||
|
"yoAe4jV2yzbd",
|
||||||
|
"13D1lOc9sqmZ"
|
||||||
|
],
|
||||||
|
"title": "Export as PDF",
|
||||||
|
"notePosition": 30,
|
||||||
|
"prefix": null,
|
||||||
|
"isExpanded": false,
|
||||||
|
"type": "text",
|
||||||
|
"mime": "text/html",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "iconClass",
|
||||||
|
"value": "bx bxs-file-pdf",
|
||||||
|
"isInheritable": false,
|
||||||
|
"position": 30
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"format": "html",
|
||||||
|
"dataFileName": "Export as PDF.html",
|
||||||
|
"attachments": [
|
||||||
|
{
|
||||||
|
"attachmentId": "xsGM34t8ssKV",
|
||||||
|
"title": "image.png",
|
||||||
|
"role": "image",
|
||||||
|
"mime": "image/png",
|
||||||
|
"position": 10,
|
||||||
|
"dataFileName": "Export as PDF_image.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attachmentId": "b3v1pLE6TF1Y",
|
||||||
|
"title": "image.png",
|
||||||
|
"role": "image",
|
||||||
|
"mime": "image/png",
|
||||||
|
"position": 10,
|
||||||
|
"dataFileName": "1_Export as PDF_image.png"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -233,8 +323,47 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"format": "html",
|
"format": "html",
|
||||||
"dataFileName": "Text.html",
|
"attachments": [],
|
||||||
"attachments": []
|
"dirFileName": "Text",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"isClone": false,
|
||||||
|
"noteId": "B0lcI9xz1r8K",
|
||||||
|
"notePath": [
|
||||||
|
"OkOZllzB3fqN",
|
||||||
|
"wmegHv51MJMd",
|
||||||
|
"crJtzsol4olb",
|
||||||
|
"B0lcI9xz1r8K"
|
||||||
|
],
|
||||||
|
"title": "Content language",
|
||||||
|
"notePosition": 10,
|
||||||
|
"prefix": null,
|
||||||
|
"isExpanded": false,
|
||||||
|
"type": "text",
|
||||||
|
"mime": "text/html",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"type": "relation",
|
||||||
|
"name": "internalLink",
|
||||||
|
"value": "3I277VKYxWDH",
|
||||||
|
"isInheritable": false,
|
||||||
|
"position": 10
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"format": "html",
|
||||||
|
"dataFileName": "Content language.html",
|
||||||
|
"attachments": [
|
||||||
|
{
|
||||||
|
"attachmentId": "OpIv6CnYCLVa",
|
||||||
|
"title": "image.png",
|
||||||
|
"role": "image",
|
||||||
|
"mime": "image/png",
|
||||||
|
"position": 10,
|
||||||
|
"dataFileName": "Content language_image.png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"isClone": false,
|
"isClone": false,
|
||||||
@ -382,7 +511,7 @@
|
|||||||
"title": "Book",
|
"title": "Book",
|
||||||
"notePosition": 70,
|
"notePosition": 70,
|
||||||
"prefix": null,
|
"prefix": null,
|
||||||
"isExpanded": true,
|
"isExpanded": false,
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"mime": "text/html",
|
"mime": "text/html",
|
||||||
"attributes": [
|
"attributes": [
|
||||||
@ -576,6 +705,14 @@
|
|||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "18_Calendar View_image.png"
|
"dataFileName": "18_Calendar View_image.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attachmentId": "JM6AU8N4MIgB",
|
||||||
|
"title": "image.png",
|
||||||
|
"role": "image",
|
||||||
|
"mime": "image/png",
|
||||||
|
"position": 10,
|
||||||
|
"dataFileName": "19_Calendar View_image.png"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -697,7 +834,7 @@
|
|||||||
"wmegHv51MJMd",
|
"wmegHv51MJMd",
|
||||||
"foPEtsL51pD2"
|
"foPEtsL51pD2"
|
||||||
],
|
],
|
||||||
"title": "Geo Map",
|
"title": "Geo map",
|
||||||
"notePosition": 120,
|
"notePosition": 120,
|
||||||
"prefix": null,
|
"prefix": null,
|
||||||
"isExpanded": false,
|
"isExpanded": false,
|
||||||
@ -713,23 +850,15 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"format": "html",
|
"format": "html",
|
||||||
"dataFileName": "Geo Map.html",
|
"dataFileName": "Geo map.html",
|
||||||
"attachments": [
|
"attachments": [
|
||||||
{
|
|
||||||
"attachmentId": "J0baLTpafs7C",
|
|
||||||
"title": "image.png",
|
|
||||||
"role": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"position": 10,
|
|
||||||
"dataFileName": "Geo Map_image.png"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"attachmentId": "kcYjOvJDFkbS",
|
"attachmentId": "kcYjOvJDFkbS",
|
||||||
"title": "image.png",
|
"title": "image.png",
|
||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "1_Geo Map_image.png"
|
"dataFileName": "Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "FDP3JzIVSnuJ",
|
"attachmentId": "FDP3JzIVSnuJ",
|
||||||
@ -737,7 +866,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "2_Geo Map_image.png"
|
"dataFileName": "1_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "eUrcqc8RRuZG",
|
"attachmentId": "eUrcqc8RRuZG",
|
||||||
@ -745,7 +874,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "3_Geo Map_image.png"
|
"dataFileName": "2_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "1quk4yxJpeHZ",
|
"attachmentId": "1quk4yxJpeHZ",
|
||||||
@ -753,7 +882,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "4_Geo Map_image.png"
|
"dataFileName": "3_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "iSpyhQ5Ya6Nk",
|
"attachmentId": "iSpyhQ5Ya6Nk",
|
||||||
@ -761,7 +890,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "5_Geo Map_image.png"
|
"dataFileName": "4_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "ut6vm2aXVfXI",
|
"attachmentId": "ut6vm2aXVfXI",
|
||||||
@ -769,7 +898,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "6_Geo Map_image.png"
|
"dataFileName": "5_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "uYdb9wWf5Nuv",
|
"attachmentId": "uYdb9wWf5Nuv",
|
||||||
@ -777,15 +906,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "7_Geo Map_image.png"
|
"dataFileName": "6_Geo map_image.png"
|
||||||
},
|
|
||||||
{
|
|
||||||
"attachmentId": "GhHYO2LteDmZ",
|
|
||||||
"title": "image.png",
|
|
||||||
"role": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"position": 10,
|
|
||||||
"dataFileName": "8_Geo Map_image.png"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "viN50n5G4kB0",
|
"attachmentId": "viN50n5G4kB0",
|
||||||
@ -793,7 +914,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "9_Geo Map_image.png"
|
"dataFileName": "7_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "mgwGrtQZjxxb",
|
"attachmentId": "mgwGrtQZjxxb",
|
||||||
@ -801,7 +922,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "10_Geo Map_image.png"
|
"dataFileName": "8_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "PMqmCbNLlZOG",
|
"attachmentId": "PMqmCbNLlZOG",
|
||||||
@ -809,7 +930,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "11_Geo Map_image.png"
|
"dataFileName": "9_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "0AwaQMqt3FVA",
|
"attachmentId": "0AwaQMqt3FVA",
|
||||||
@ -817,7 +938,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "12_Geo Map_image.png"
|
"dataFileName": "10_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "gR2c2Thmfy3I",
|
"attachmentId": "gR2c2Thmfy3I",
|
||||||
@ -825,7 +946,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "13_Geo Map_image.png"
|
"dataFileName": "11_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "JULizn130rVI",
|
"attachmentId": "JULizn130rVI",
|
||||||
@ -833,7 +954,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "14_Geo Map_image.png"
|
"dataFileName": "12_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "MdC0DpifJwu4",
|
"attachmentId": "MdC0DpifJwu4",
|
||||||
@ -841,7 +962,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "15_Geo Map_image.png"
|
"dataFileName": "13_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "gFR2Izzp18LQ",
|
"attachmentId": "gFR2Izzp18LQ",
|
||||||
@ -849,7 +970,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "16_Geo Map_image.png"
|
"dataFileName": "14_Geo map_image.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "42AncDs7SSAf",
|
"attachmentId": "42AncDs7SSAf",
|
||||||
@ -857,15 +978,7 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "17_Geo Map_image.png"
|
"dataFileName": "15_Geo map_image.png"
|
||||||
},
|
|
||||||
{
|
|
||||||
"attachmentId": "pKdtiq4r0eFY",
|
|
||||||
"title": "image.png",
|
|
||||||
"role": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"position": 10,
|
|
||||||
"dataFileName": "18_Geo Map_image.png"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"attachmentId": "FXRVvYpOxWyR",
|
"attachmentId": "FXRVvYpOxWyR",
|
||||||
@ -873,7 +986,23 @@
|
|||||||
"role": "image",
|
"role": "image",
|
||||||
"mime": "image/png",
|
"mime": "image/png",
|
||||||
"position": 10,
|
"position": 10,
|
||||||
"dataFileName": "19_Geo Map_image.png"
|
"dataFileName": "16_Geo map_image.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attachmentId": "qudP7UCtwIq3",
|
||||||
|
"title": "image.png",
|
||||||
|
"role": "image",
|
||||||
|
"mime": "image/jpg",
|
||||||
|
"position": 10,
|
||||||
|
"dataFileName": "17_Geo map_image.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attachmentId": "utecGxWk08QY",
|
||||||
|
"title": "image.png",
|
||||||
|
"role": "image",
|
||||||
|
"mime": "image/png",
|
||||||
|
"position": 10,
|
||||||
|
"dataFileName": "18_Geo map_image.png"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -943,173 +1072,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"isClone": false,
|
|
||||||
"noteId": "DtJJ20yEozPA",
|
|
||||||
"notePath": [
|
|
||||||
"OkOZllzB3fqN",
|
|
||||||
"DtJJ20yEozPA"
|
|
||||||
],
|
|
||||||
"title": "Theme development",
|
|
||||||
"notePosition": 130,
|
|
||||||
"prefix": null,
|
|
||||||
"isExpanded": false,
|
|
||||||
"type": "text",
|
|
||||||
"mime": "text/html",
|
|
||||||
"attributes": [
|
|
||||||
{
|
|
||||||
"type": "label",
|
|
||||||
"name": "iconClass",
|
|
||||||
"value": "bx bx-palette",
|
|
||||||
"isInheritable": false,
|
|
||||||
"position": 10
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"format": "html",
|
|
||||||
"attachments": [],
|
|
||||||
"dirFileName": "Theme development",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"isClone": false,
|
|
||||||
"noteId": "5HH79ztN0fZA",
|
|
||||||
"notePath": [
|
|
||||||
"OkOZllzB3fqN",
|
|
||||||
"DtJJ20yEozPA",
|
|
||||||
"5HH79ztN0fZA"
|
|
||||||
],
|
|
||||||
"title": "Creating a custom theme",
|
|
||||||
"notePosition": 10,
|
|
||||||
"prefix": null,
|
|
||||||
"isExpanded": false,
|
|
||||||
"type": "text",
|
|
||||||
"mime": "text/html",
|
|
||||||
"attributes": [
|
|
||||||
{
|
|
||||||
"type": "relation",
|
|
||||||
"name": "internalLink",
|
|
||||||
"value": "aH8Dk5aMiq7R",
|
|
||||||
"isInheritable": false,
|
|
||||||
"position": 10
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"format": "html",
|
|
||||||
"dataFileName": "Creating a custom theme.html",
|
|
||||||
"attachments": [
|
|
||||||
{
|
|
||||||
"attachmentId": "AJHVfQtIQgJ7",
|
|
||||||
"title": "image.png",
|
|
||||||
"role": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"position": 10,
|
|
||||||
"dataFileName": "Creating a custom theme_im.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"attachmentId": "gXLyv5KXjfxg",
|
|
||||||
"title": "image.png",
|
|
||||||
"role": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"position": 10,
|
|
||||||
"dataFileName": "1_Creating a custom theme_im.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"attachmentId": "on1gD7BzCWdN",
|
|
||||||
"title": "image.png",
|
|
||||||
"role": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"position": 10,
|
|
||||||
"dataFileName": "2_Creating a custom theme_im.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"attachmentId": "17p6z24yW5eP",
|
|
||||||
"title": "image.png",
|
|
||||||
"role": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"position": 10,
|
|
||||||
"dataFileName": "3_Creating a custom theme_im.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"attachmentId": "K3cdwj8f90m0",
|
|
||||||
"title": "image.png",
|
|
||||||
"role": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"position": 10,
|
|
||||||
"dataFileName": "4_Creating a custom theme_im.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"attachmentId": "bn93hwF7C8sR",
|
|
||||||
"title": "image.png",
|
|
||||||
"role": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"position": 10,
|
|
||||||
"dataFileName": "5_Creating a custom theme_im.png"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"isClone": false,
|
|
||||||
"noteId": "aH8Dk5aMiq7R",
|
|
||||||
"notePath": [
|
|
||||||
"OkOZllzB3fqN",
|
|
||||||
"DtJJ20yEozPA",
|
|
||||||
"aH8Dk5aMiq7R"
|
|
||||||
],
|
|
||||||
"title": "Customize the Next theme",
|
|
||||||
"notePosition": 20,
|
|
||||||
"prefix": null,
|
|
||||||
"isExpanded": false,
|
|
||||||
"type": "text",
|
|
||||||
"mime": "text/html",
|
|
||||||
"attributes": [],
|
|
||||||
"format": "html",
|
|
||||||
"dataFileName": "Customize the Next theme.html",
|
|
||||||
"attachments": [
|
|
||||||
{
|
|
||||||
"attachmentId": "5z4bC0x0eH0P",
|
|
||||||
"title": "image.png",
|
|
||||||
"role": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"position": 10,
|
|
||||||
"dataFileName": "Customize the Next theme_i.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"attachmentId": "u0zkXkD7rGXA",
|
|
||||||
"title": "image.png",
|
|
||||||
"role": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"position": 10,
|
|
||||||
"dataFileName": "1_Customize the Next theme_i.png"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"isClone": false,
|
|
||||||
"noteId": "pMq6N1oBV9oo",
|
|
||||||
"notePath": [
|
|
||||||
"OkOZllzB3fqN",
|
|
||||||
"DtJJ20yEozPA",
|
|
||||||
"pMq6N1oBV9oo"
|
|
||||||
],
|
|
||||||
"title": "Reference",
|
|
||||||
"notePosition": 30,
|
|
||||||
"prefix": null,
|
|
||||||
"isExpanded": false,
|
|
||||||
"type": "text",
|
|
||||||
"mime": "text/html",
|
|
||||||
"attributes": [
|
|
||||||
{
|
|
||||||
"type": "relation",
|
|
||||||
"name": "internalLink",
|
|
||||||
"value": "po38jIc0LD2H",
|
|
||||||
"isInheritable": false,
|
|
||||||
"position": 10
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"format": "html",
|
|
||||||
"dataFileName": "Reference.html",
|
|
||||||
"attachments": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"isClone": false,
|
"isClone": false,
|
||||||
"noteId": "LTnkDnYmmZ7s",
|
"noteId": "LTnkDnYmmZ7s",
|
||||||
@ -1283,7 +1245,7 @@
|
|||||||
"title": "ETAPI",
|
"title": "ETAPI",
|
||||||
"notePosition": 10,
|
"notePosition": 10,
|
||||||
"prefix": null,
|
"prefix": null,
|
||||||
"isExpanded": true,
|
"isExpanded": false,
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"mime": "text/html",
|
"mime": "text/html",
|
||||||
"attributes": [],
|
"attributes": [],
|
||||||
@ -1333,7 +1295,7 @@
|
|||||||
"title": "Internal API",
|
"title": "Internal API",
|
||||||
"notePosition": 20,
|
"notePosition": 20,
|
||||||
"prefix": null,
|
"prefix": null,
|
||||||
"isExpanded": true,
|
"isExpanded": false,
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"mime": "text/html",
|
"mime": "text/html",
|
||||||
"attributes": [],
|
"attributes": [],
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 340 B |
|
After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
@ -23,7 +23,7 @@
|
|||||||
as PDF. On the server or PWA (mobile), the option is not available due
|
as PDF. On the server or PWA (mobile), the option is not available due
|
||||||
to technical constraints and it will be hidden.</p>
|
to technical constraints and it will be hidden.</p>
|
||||||
<p>To print a note, select the
|
<p>To print a note, select the
|
||||||
<img src="2_Export as PDF_image.png" width="29"
|
<img src="1_Export as PDF_image.png" width="29"
|
||||||
height="31">button to the right of the note and select <i>Export as PDF</i>.</p>
|
height="31">button to the right of the note and select <i>Export as PDF</i>.</p>
|
||||||
<p>Afterwards you will be prompted to select where to save the PDF file.
|
<p>Afterwards you will be prompted to select where to save the PDF file.
|
||||||
Upon confirmation, the resulting PDF will be opened automatically using
|
Upon confirmation, the resulting PDF will be opened automatically using
|
||||||
@ -33,7 +33,7 @@
|
|||||||
<a
|
<a
|
||||||
href="#root/OeKBfN6JbMIq/jRV1MPt4mNSP/hrC6xn7hnDq5">report the issue</a>. In this case, it's best to offer a sample note (click
|
href="#root/OeKBfN6JbMIq/jRV1MPt4mNSP/hrC6xn7hnDq5">report the issue</a>. In this case, it's best to offer a sample note (click
|
||||||
on the
|
on the
|
||||||
<img src="2_Export as PDF_image.png" width="29" height="31">button, select Export note → This note and all of its descendants → HTML
|
<img src="1_Export as PDF_image.png" width="29" height="31">button, select Export note → This note and all of its descendants → HTML
|
||||||
in ZIP archive). Make sure not to accidentally leak any personal information.</p>
|
in ZIP archive). Make sure not to accidentally leak any personal information.</p>
|
||||||
<h2>Landscape mode</h2>
|
<h2>Landscape mode</h2>
|
||||||
<p>When exporting to PDF, there are no customizable settings such as page
|
<p>When exporting to PDF, there are no customizable settings such as page
|
||||||
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
@ -0,0 +1,56 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="../../style.css">
|
||||||
|
<base target="_parent">
|
||||||
|
<title data-trilium-title>Right-to-left text notes</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="content">
|
||||||
|
<h1 data-trilium-h1>Right-to-left text notes</h1>
|
||||||
|
|
||||||
|
<div class="ck-content">
|
||||||
|
<p>Trilium now has basic support for right-to-left text, at note level.</p>
|
||||||
|
<figure
|
||||||
|
class="table">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<figure class="image">
|
||||||
|
<img style="aspect-ratio:906/557;" src="3_Right-to-left text notes_i.png"
|
||||||
|
width="906" height="557">
|
||||||
|
</figure>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<figure class="image">
|
||||||
|
<img style="aspect-ratio:906/557;" src="2_Right-to-left text notes_i.png"
|
||||||
|
width="906" height="557">
|
||||||
|
</figure>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</figure>
|
||||||
|
<p>Note that only the Text note type supports this.</p>
|
||||||
|
<p>The list of languages is configurable via the a new dedicated settings
|
||||||
|
page:</p>
|
||||||
|
<figure class="image">
|
||||||
|
<img style="aspect-ratio:1248/635;" src="4_Right-to-left text notes_i.png"
|
||||||
|
width="1248" height="635">
|
||||||
|
</figure>
|
||||||
|
<p>To select the corresponding language of the text, go to “Basic Properties”
|
||||||
|
and select your desired language.</p>
|
||||||
|
<p>
|
||||||
|
<img src="1_Right-to-left text notes_i.png" width="635" height="492">
|
||||||
|
</p>
|
||||||
|
<p>Feel free to report any issues regarding right to left support.</p>
|
||||||
|
<p> </p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 323 KiB After Width: | Height: | Size: 323 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 191 KiB After Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 515 KiB After Width: | Height: | Size: 515 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 397 KiB After Width: | Height: | Size: 397 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
@ -118,6 +118,12 @@
|
|||||||
<td>When present (regardless of value), it will show the number of the week
|
<td>When present (regardless of value), it will show the number of the week
|
||||||
on the calendar.</td>
|
on the calendar.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>~child:template</code>
|
||||||
|
</td>
|
||||||
|
<td>Defines the template for newly created notes in the calendar (via dragging
|
||||||
|
or clicking).</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</figure>
|
</figure>
|
||||||
@ -175,6 +181,36 @@
|
|||||||
than the title, either a label (e.g. <code>#assignee</code>) or a relation
|
than the title, either a label (e.g. <code>#assignee</code>) or a relation
|
||||||
(e.g. <code>~for</code>). See <i>Advanced use-cases</i> for more information.</td>
|
(e.g. <code>~for</code>). See <i>Advanced use-cases</i> for more information.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>#calendar:promotedAttributes</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<p>Allows displaying the value of one or more promoted attributes in the
|
||||||
|
calendar like this:
|
||||||
|
<img src="19_Calendar View_image.png" width="131" height="113">
|
||||||
|
</p><pre><code class="language-text-x-trilium-auto">#label:weight="promoted,number,single,precision=1"
|
||||||
|
#label:mood="promoted,alias=Mood,single,text"
|
||||||
|
#calendar:promotedAttributes="label:weight,label:mood" </code></pre>
|
||||||
|
<p>It can also be used with relations, case in which it will display the
|
||||||
|
title of the target note:</p><pre><code class="language-text-x-trilium-auto">#relation:assignee="promoted,alias=Assignee,single,text"
|
||||||
|
#calendar:promotedAttributes="relation:assignee"
|
||||||
|
~assignee=@My assignee </code></pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>#calendar:startDate</code>
|
||||||
|
</td>
|
||||||
|
<td>Allows using a different label to represent the start date, other than <code>#startDate</code> (e.g. <code>#expiryDate</code>).
|
||||||
|
The label name must be prefixed with <code>#</code>. If the label is not
|
||||||
|
defined for a note, the default will be used instead.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>#calendar:endDate</code>
|
||||||
|
</td>
|
||||||
|
<td>Allows using a different label to represent the start date, other than <code>#endDate</code>.
|
||||||
|
The label name must be prefixed with <code>#</code>. If the label is not
|
||||||
|
defined for a note, the default will be used instead.</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</figure>
|
</figure>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 6.5 KiB |
@ -5,12 +5,12 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="../../style.css">
|
<link rel="stylesheet" href="../../style.css">
|
||||||
<base target="_parent">
|
<base target="_parent">
|
||||||
<title data-trilium-title>Geo Map</title>
|
<title data-trilium-title>Geo map</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h1 data-trilium-h1>Geo Map</h1>
|
<h1 data-trilium-h1>Geo map</h1>
|
||||||
|
|
||||||
<div class="ck-content">
|
<div class="ck-content">
|
||||||
<h2>Creating a new geo map</h2>
|
<h2>Creating a new geo map</h2>
|
||||||
@ -26,7 +26,7 @@
|
|||||||
<th>1</th>
|
<th>1</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image image_resized" style="width:100%;">
|
<figure class="image image_resized" style="width:100%;">
|
||||||
<img style="aspect-ratio:1256/1044;" src="9_Geo Map_image.png" width="1256"
|
<img style="aspect-ratio:1256/1044;" src="7_Geo map_image.png" width="1256"
|
||||||
height="1044">
|
height="1044">
|
||||||
</figure>
|
</figure>
|
||||||
</td>
|
</td>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
<th>2</th>
|
<th>2</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image image_resized" style="width:100%;">
|
<figure class="image image_resized" style="width:100%;">
|
||||||
<img style="aspect-ratio:1720/1396;" src="3_Geo Map_image.png" width="1720"
|
<img style="aspect-ratio:1720/1396;" src="2_Geo map_image.png" width="1720"
|
||||||
height="1396">
|
height="1396">
|
||||||
</figure>
|
</figure>
|
||||||
</td>
|
</td>
|
||||||
@ -69,18 +69,18 @@
|
|||||||
<p>To create a marker, first navigate to the desired point on the map. Then
|
<p>To create a marker, first navigate to the desired point on the map. Then
|
||||||
press the
|
press the
|
||||||
<img class="image_resized" style="aspect-ratio:72/66;width:7.37%;"
|
<img class="image_resized" style="aspect-ratio:72/66;width:7.37%;"
|
||||||
src="4_Geo Map_image.png" width="72" height="66">button on the top-right of the map.</p>
|
src="3_Geo map_image.png" width="72" height="66">button on the top-right of the map.</p>
|
||||||
<p>If the button is not visible, make sure the button section is visible
|
<p>If the button is not visible, make sure the button section is visible
|
||||||
by pressing the chevron button (
|
by pressing the chevron button (
|
||||||
<img class="image_resized" style="aspect-ratio:72/66;width:7.51%;"
|
<img class="image_resized" style="aspect-ratio:72/66;width:7.51%;"
|
||||||
src="10_Geo Map_image.png" width="72" height="66">) in the top-right of the map.</p>
|
src="8_Geo map_image.png" width="72" height="66">) in the top-right of the map.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>2</th>
|
<th>2</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image image_resized" style="width:100%;">
|
<figure class="image image_resized" style="width:100%;">
|
||||||
<img style="aspect-ratio:1730/416;" src="14_Geo Map_image.png" width="1730"
|
<img style="aspect-ratio:1730/416;" src="12_Geo map_image.png" width="1730"
|
||||||
height="416">
|
height="416">
|
||||||
</figure>
|
</figure>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
@ -96,7 +96,7 @@
|
|||||||
<th>3</th>
|
<th>3</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image">
|
<figure class="image">
|
||||||
<img style="aspect-ratio:1586/404;" src="1_Geo Map_image.png" width="1586"
|
<img style="aspect-ratio:1586/404;" src="Geo map_image.png" width="1586"
|
||||||
height="404">
|
height="404">
|
||||||
</figure>
|
</figure>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
@ -107,7 +107,7 @@
|
|||||||
<th>4</th>
|
<th>4</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image">
|
<figure class="image">
|
||||||
<img style="aspect-ratio:1696/608;" src="6_Geo Map_image.png" width="1696"
|
<img style="aspect-ratio:1696/608;" src="5_Geo map_image.png" width="1696"
|
||||||
height="608">
|
height="608">
|
||||||
</figure>
|
</figure>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
@ -122,7 +122,7 @@
|
|||||||
<p>The location of a marker is stored in the <code>#geolocation</code> attribute
|
<p>The location of a marker is stored in the <code>#geolocation</code> attribute
|
||||||
of the child notes:</p>
|
of the child notes:</p>
|
||||||
<figure class="image">
|
<figure class="image">
|
||||||
<img style="aspect-ratio:1288/278;" src="12_Geo Map_image.png" width="1288"
|
<img style="aspect-ratio:1288/278;" src="10_Geo map_image.png" width="1288"
|
||||||
height="278">
|
height="278">
|
||||||
</figure>
|
</figure>
|
||||||
<p>This value can be added manually if needed. The value of the attribute
|
<p>This value can be added manually if needed. The value of the attribute
|
||||||
@ -155,6 +155,13 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<h2>Icon and color of the markers</h2>
|
||||||
|
<p>
|
||||||
|
<img src="18_Geo map_image.png" alt="image" width="523" height="295">
|
||||||
|
</p>
|
||||||
|
<p>The markers will have the same icon as the note.</p>
|
||||||
|
<p>It's possible to add a custom color to a marker by assigning them a <code>#color</code> attribute
|
||||||
|
such as <code>#color=green</code>.</p>
|
||||||
<h2>Adding the coordinates manually</h2>
|
<h2>Adding the coordinates manually</h2>
|
||||||
<p>In a nutshell, create a child note and set the <code>#geolocation</code> attribute
|
<p>In a nutshell, create a child note and set the <code>#geolocation</code> attribute
|
||||||
to the coordinates.</p>
|
to the coordinates.</p>
|
||||||
@ -168,7 +175,7 @@
|
|||||||
<th>1</th>
|
<th>1</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image image-style-align-center image_resized" style="width:100%;">
|
<figure class="image image-style-align-center image_resized" style="width:100%;">
|
||||||
<img style="aspect-ratio:732/918;" src="16_Geo Map_image.png" width="732"
|
<img style="aspect-ratio:732/918;" src="14_Geo map_image.png" width="732"
|
||||||
height="918">
|
height="918">
|
||||||
</figure>
|
</figure>
|
||||||
</td>
|
</td>
|
||||||
@ -185,7 +192,7 @@
|
|||||||
<th>2</th>
|
<th>2</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image image_resized" style="width:100%;">
|
<figure class="image image_resized" style="width:100%;">
|
||||||
<img style="aspect-ratio:518/84;" src="19_Geo Map_image.png" width="518"
|
<img style="aspect-ratio:518/84;" src="16_Geo map_image.png" width="518"
|
||||||
height="84">
|
height="84">
|
||||||
</figure>
|
</figure>
|
||||||
</td>
|
</td>
|
||||||
@ -199,7 +206,7 @@
|
|||||||
<th>3</th>
|
<th>3</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image image_resized" style="width:100%;">
|
<figure class="image image_resized" style="width:100%;">
|
||||||
<img style="aspect-ratio:1074/276;" src="11_Geo Map_image.png" width="1074"
|
<img style="aspect-ratio:1074/276;" src="9_Geo map_image.png" width="1074"
|
||||||
height="276">
|
height="276">
|
||||||
</figure>
|
</figure>
|
||||||
</td>
|
</td>
|
||||||
@ -225,7 +232,7 @@
|
|||||||
<th>1</th>
|
<th>1</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image image_resized" style="width:100%;">
|
<figure class="image image_resized" style="width:100%;">
|
||||||
<img style="aspect-ratio:562/454;" src="17_Geo Map_image.png" width="562"
|
<img style="aspect-ratio:562/454;" src="15_Geo map_image.png" width="562"
|
||||||
height="454">
|
height="454">
|
||||||
</figure>
|
</figure>
|
||||||
</td>
|
</td>
|
||||||
@ -236,7 +243,7 @@
|
|||||||
<th>2</th>
|
<th>2</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image image_resized" style="width:100%;">
|
<figure class="image image_resized" style="width:100%;">
|
||||||
<img style="aspect-ratio:696/480;" src="13_Geo Map_image.png" width="696"
|
<img style="aspect-ratio:696/480;" src="11_Geo map_image.png" width="696"
|
||||||
height="480">
|
height="480">
|
||||||
</figure>
|
</figure>
|
||||||
</td>
|
</td>
|
||||||
@ -250,7 +257,7 @@
|
|||||||
<th>3</th>
|
<th>3</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image">
|
<figure class="image">
|
||||||
<img style="aspect-ratio:640/276;" src="2_Geo Map_image.png" width="640"
|
<img style="aspect-ratio:640/276;" src="1_Geo map_image.png" width="640"
|
||||||
height="276">
|
height="276">
|
||||||
</figure>
|
</figure>
|
||||||
</td>
|
</td>
|
||||||
@ -275,7 +282,7 @@
|
|||||||
<th>1</th>
|
<th>1</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image">
|
<figure class="image">
|
||||||
<img style="aspect-ratio:226/74;" src="7_Geo Map_image.png" width="226"
|
<img style="aspect-ratio:226/74;" src="6_Geo map_image.png" width="226"
|
||||||
height="74">
|
height="74">
|
||||||
</figure>
|
</figure>
|
||||||
</td>
|
</td>
|
||||||
@ -286,7 +293,7 @@
|
|||||||
<th>2</th>
|
<th>2</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image">
|
<figure class="image">
|
||||||
<img style="aspect-ratio:322/222;" src="5_Geo Map_image.png" width="322"
|
<img style="aspect-ratio:322/222;" src="4_Geo map_image.png" width="322"
|
||||||
height="222">
|
height="222">
|
||||||
</figure>
|
</figure>
|
||||||
</td>
|
</td>
|
||||||
@ -297,7 +304,7 @@
|
|||||||
<th>3</th>
|
<th>3</th>
|
||||||
<td>
|
<td>
|
||||||
<figure class="image image_resized" style="width:100%;">
|
<figure class="image image_resized" style="width:100%;">
|
||||||
<img style="aspect-ratio:620/530;" src="15_Geo Map_image.png" width="620"
|
<img style="aspect-ratio:620/530;" src="13_Geo map_image.png" width="620"
|
||||||
height="530">
|
height="530">
|
||||||
</figure>
|
</figure>
|
||||||
</td>
|
</td>
|
||||||
@ -310,9 +317,16 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</figure>
|
</figure>
|
||||||
<p> </p>
|
<h2>Troubleshooting</h2>
|
||||||
<p> </p>
|
<h3>Grid-like artifacts on the map</h3>
|
||||||
<p> </p>
|
<p>
|
||||||
|
<img class="image_resized" style="aspect-ratio:678/499;width:58%;" src="17_Geo map_image.png"
|
||||||
|
width="678" height="499">
|
||||||
|
</p>
|
||||||
|
<p>This occurs if the application is not at 100% zoom which causes the pixels
|
||||||
|
of the map to not render correctly due to fractional scaling. The only
|
||||||
|
possible solution i to set the UI zoom at 100% (default keyboard shortcut
|
||||||
|
is Ctrl+0).</p>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
@ -1,19 +0,0 @@
|
|||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link rel="stylesheet" href="../../style.css">
|
|
||||||
<base target="_parent">
|
|
||||||
<title data-trilium-title>Text</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="content">
|
|
||||||
<h1 data-trilium-h1>Text</h1>
|
|
||||||
|
|
||||||
<div class="ck-content"></div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="../../../style.css">
|
||||||
|
<base target="_parent">
|
||||||
|
<title data-trilium-title>Content language</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="content">
|
||||||
|
<h1 data-trilium-h1>Content language</h1>
|
||||||
|
|
||||||
|
<div class="ck-content">
|
||||||
|
<p>A language hint can be provided for text notes. This option informs the
|
||||||
|
browser or the desktop application about the language the note is written
|
||||||
|
in (for example this might help with spellchecking), and it also determines
|
||||||
|
whether the text is displayed from right-to-left for languages such as
|
||||||
|
Arabic, Hebrew, etc.</p>
|
||||||
|
<p>For more information about right-to-left support, see <a class="reference-link"
|
||||||
|
href="../../New%20Features/Right-to-left%20text%20notes.html">Right-to-left text notes</a>.</p>
|
||||||
|
<p>To set the language of the content, go to “Basic Properties” and look
|
||||||
|
for the “Language” field. By default there will be no content languages
|
||||||
|
set, they can be configured by going to settings or by selecting the “Configure
|
||||||
|
languages” item in the list.</p>
|
||||||
|
<p>
|
||||||
|
<img src="Content language_image.png" width="635" height="492">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||