Merge branch 'develop' into renovate/eslint-plugin-playwright-2.x

This commit is contained in:
Elian Doran 2025-05-03 21:04:28 +03:00 committed by GitHub
commit e51e66cdfc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 859 additions and 203 deletions

View File

@ -39,7 +39,7 @@ jobs:
- uses: nrwl/nx-set-shas@v4
- name: Check affected
run: pnpm nx affected -t rebuild-deps
run: pnpm nx affected -t build rebuild-deps
report-electron-size:
name: Report Electron size

View File

@ -8,7 +8,7 @@ TriliumNext Notes is an open-source, cross-platform hierarchical note taking app
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="https://github.com/TriliumNext/Notes/blob/develop/images/screenshots/app.png?raw=true" alt="Trilium Screenshot" width="1000"></a>
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⚠️ Why TriliumNext?

View File

@ -35,7 +35,7 @@
"chore:generate-openapi": "tsx bin/generate-openapi.js"
},
"devDependencies": {
"@playwright/test": "1.51.1",
"@playwright/test": "1.52.0",
"@stylistic/eslint-plugin": "4.2.0",
"@types/express": "5.0.1",
"@types/node": "22.15.3",

17
apps/db-compare/README.md Normal file
View File

@ -0,0 +1,17 @@
# Database compare tool
> [!IMPORTANT]
> The original implementation was signficantly out of date. While we have made the effort of updating dependencies and getting it to run, currently it only compares the old database structure (v214).
To build and run manually:
```sh
nx build db-compare
node ./apps/db-compare/dist/compare.js
```
To serve development build with arguments:
```sh
nx serve db-compare --args "apps/server/spec/db/document_v214.db" --args "apps/server/spec/db/document_v214_migrated.db"
```

View File

@ -0,0 +1,5 @@
import baseConfig from "../../eslint.config.mjs";
export default [
...baseConfig
];

View File

@ -0,0 +1,75 @@
{
"name": "@triliumnext/db-compare",
"version": "0.0.1",
"private": true,
"description": "Tool to compare content of Trilium databases. Useful for debugging sync problems.",
"dependencies": {
"colors": "1.4.0",
"diff": "7.0.0",
"sqlite": "5.1.1",
"sqlite3": "5.1.5"
},
"nx": {
"name": "db-compare",
"targets": {
"build": {
"executor": "@nx/esbuild:esbuild",
"outputs": [
"{options.outputPath}"
],
"defaultConfiguration": "production",
"options": {
"platform": "node",
"outputPath": "apps/db-compare/dist",
"format": [
"cjs"
],
"bundle": false,
"main": "apps/db-compare/src/compare.ts",
"tsConfig": "apps/db-compare/tsconfig.app.json",
"assets": [],
"esbuildOptions": {
"sourcemap": true,
"outExtension": {
".js": ".js"
}
}
},
"configurations": {
"development": {},
"production": {
"esbuildOptions": {
"sourcemap": false,
"outExtension": {
".js": ".js"
}
}
}
}
},
"serve": {
"executor": "@nx/js:node",
"defaultConfiguration": "development",
"dependsOn": [
"build"
],
"options": {
"buildTarget": "db-compare:build",
"runBuildTargetDependencies": false
},
"configurations": {
"development": {
"buildTarget": "db-compare:build:development"
},
"production": {
"buildTarget": "db-compare:build:production"
}
}
}
}
},
"devDependencies": {
"@types/colors": "1.2.4",
"@types/diff": "^7.0.2"
}
}

View File

@ -0,0 +1,137 @@
"use strict";
import * as jsDiff from "diff";
import * as sqlite from "sqlite";
import * as sqlite3 from "sqlite3";
import sql from "./sql.js";
import "colors";
import path from "path";
function printDiff(one: string, two: string) {
const diff = jsDiff.diffChars(one, two);
diff.forEach(function(part){
// green for additions, red for deletions
// grey for common parts
const color = part.added ? 'green' :
part.removed ? 'red' : 'grey';
process.stderr.write(part.value[color]);
});
console.log("");
}
function checkMissing(table: string, name: string, ids1: string[], ids2: string[]) {
const missing = ids1.filter(item => ids2.indexOf(item) < 0);
if (missing.length > 0) {
console.log("Missing IDs from " + name + " table " + table + ": ", missing);
}
}
function handleBuffer(obj: { content: Buffer | string }) {
if (obj && Buffer.isBuffer(obj.content)) {
obj.content = obj.content.toString();
}
return obj;
}
function compareRows(table: string, rsLeft: Record<string, any>, rsRight: Record<string, any>, column: string) {
const leftIds = Object.keys(rsLeft);
const rightIds = Object.keys(rsRight);
console.log("");
console.log("--------------------------------------------------------");
console.log(`${table} - ${leftIds.length}/${rightIds.length}`);
checkMissing(table, "right", leftIds, rightIds);
checkMissing(table, "left", rightIds, leftIds);
const commonIds = leftIds.filter(item => rightIds.includes(item));
for (const id of commonIds) {
const valueLeft = handleBuffer(rsLeft[id]);
const valueRight = handleBuffer(rsRight[id]);
const left = JSON.stringify(valueLeft, null, 2);
const right = JSON.stringify(valueRight, null, 2);
if (left !== right) {
console.log("Table " + table + " row with " + column + "=" + id + " differs:");
console.log("Left: ", left);
console.log("Right: ", right);
printDiff(left, right);
}
}
}
async function main() {
const dbLeftPath = process.argv.at(-2);
const dbRightPath = process.argv.at(-1);
if (process.argv.length < 4 || !dbLeftPath || !dbRightPath) {
console.log(`Usage: ${process.argv[0]} ${process.argv[1]} path/to/first.db path/to/second.db`);
process.exit(1);
}
let dbLeft: sqlite.Database;
let dbRight: sqlite.Database;
try {
dbLeft = await sqlite.open({filename: dbLeftPath, driver: sqlite3.Database});
} catch (e: any) {
console.error(`Could not load first database at ${path.resolve(dbRightPath)} due to: ${e.message}`);
process.exit(2);
}
try {
dbRight = await sqlite.open({filename: dbRightPath, driver: sqlite3.Database});
} catch (e: any) {
console.error(`Could not load second database at ${path.resolve(dbRightPath)} due to: ${e.message}`);
process.exit(3);
}
async function compare(table: string, column: string, query: string) {
const rsLeft = await sql.getIndexed(dbLeft, column, query);
const rsRight = await sql.getIndexed(dbRight, column, query);
compareRows(table, rsLeft, rsRight, column);
}
await compare("branches", "branchId",
"SELECT branchId, noteId, parentNoteId, notePosition, utcDateModified, isDeleted, prefix FROM branches");
await compare("notes", "noteId",
"SELECT noteId, title, dateCreated, utcDateCreated, isProtected, isDeleted FROM notes WHERE isDeleted = 0");
await compare("note_contents", "noteId",
"SELECT note_contents.noteId, note_contents.content FROM note_contents JOIN notes USING(noteId) WHERE isDeleted = 0");
await compare("note_revisions", "noteRevisionId",
"SELECT noteRevisionId, noteId, title, dateCreated, dateLastEdited, utcDateCreated, utcDateLastEdited, isProtected FROM note_revisions");
await compare("note_revision_contents", "noteRevisionId",
"SELECT noteRevisionId, content FROM note_revision_contents");
await compare("options", "name",
`SELECT name, value, utcDateModified FROM options WHERE isSynced = 1`);
await compare("attributes", "attributeId",
"SELECT attributeId, noteId, type, name, value FROM attributes");
await compare("etapi_tokens", "etapiTokenId",
"SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified, isDeleted FROM etapi_tokens");
await compare("entity_changes", "uniqueId",
"SELECT entityName || '-' || entityId AS uniqueId, hash, isErased, utcDateChanged FROM entity_changes WHERE isSynced = 1");
}
(async () => {
try {
await main();
} catch (e) {
console.error(e);
}
})();

View File

@ -0,0 +1,90 @@
"use strict";
import type { Database } from "sqlite";
async function getSingleResult(db: Database, query: string, params: any[] = []) {
return await wrap(db, async db => db.get(query, ...params));
}
async function getSingleResultOrNull(db: Database, query: string, params: any[] = []) {
const all = await wrap(db, async db => db.all(query, ...params));
return all.length > 0 ? all[0] : null;
}
async function getSingleValue(db: Database, query: string, params: any[] = []) {
const row = await getSingleResultOrNull(db, query, params);
if (!row) {
return null;
}
return row[Object.keys(row)[0]];
}
async function getResults(db: Database, query: string, params: any[] = []) {
return await wrap(db, async db => db.all(query, ...params));
}
async function getIndexed(db: Database, column: string, query: string, params: any[] = []) {
const results = await getResults(db, query, params);
const map: Record<string, any> = {};
for (const row of results) {
map[row[column]] = row;
}
return map;
}
async function getMap(db: Database, query: string, params: any[] = []) {
const map: Record<string, any> = {};
const results = await getResults(db, query, params);
for (const row of results) {
const keys = Object.keys(row);
map[row[keys[0]]] = row[keys[1]];
}
return map;
}
async function getFlattenedResults(db: Database, key: string, query: string, params: any[] = []) {
const list = [];
const result = await getResults(db, query, params);
for (const row of result) {
list.push(row[key]);
}
return list;
}
async function execute(db: Database, query: string, params: any[] = []) {
return await wrap(db, async db => db.run(query, ...params));
}
async function wrap<T>(db: Database, func: (db: Database) => Promise<T>) {
const thisError = new Error();
try {
return await func(db);
} catch (e: any) {
console.error("Error executing query. Inner exception: " + e.stack + thisError.stack);
throw thisError;
}
}
export default {
getSingleValue,
getSingleResult,
getSingleResultOrNull,
getResults,
getIndexed,
getMap,
getFlattenedResults,
execute
};

View File

@ -0,0 +1,20 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"types": [
"node"
],
"rootDir": "src",
"tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo",
"verbatimModuleSyntax": false
},
"include": [
"src/**/*.ts"
],
"exclude": [
"eslint.config.js",
"eslint.config.cjs",
"eslint.config.mjs"
]
}

View File

@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
}
]
}

View File

@ -33,7 +33,7 @@
"config": {
"forge": "../electron-forge/forge.config.cjs"
},
"packageManager": "pnpm@10.9.0+sha512.0486e394640d3c1fb3c9d43d49cf92879ff74f8516959c235308f5a8f62e2e19528a65cdc2a3058f587cde71eba3d5b56327c8c33a97e4c4051ca48a10ca2d5f",
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39",
"scripts": {
"start-prod": "nx build desktop && cross-env TRILIUM_DATA_DIR=data TRILIUM_RESOURCE_DIR=dist TRILIUM_PORT=37841 electron dist/main.js"
},
@ -48,7 +48,9 @@
"targets": {
"rebuild-deps": {
"executor": "nx:run-commands",
"dependsOn": [ "build" ],
"dependsOn": [
"build"
],
"defaultConfiguration": "default",
"cache": true,
"configurations": {
@ -64,7 +66,9 @@
},
"serve": {
"executor": "nx:run-commands",
"dependsOn": [ "rebuild-deps" ],
"dependsOn": [
"rebuild-deps"
],
"defaultConfiguration": "default",
"configurations": {
"default": {
@ -79,11 +83,15 @@
}
},
"electron-forge:make": {
"dependsOn": [ "build" ],
"dependsOn": [
"build"
],
"command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm electron-forge make dist"
},
"electron-forge:package": {
"dependsOn": [ "build" ],
"dependsOn": [
"build"
],
"command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm electron-forge package dist"
}
}

View File

@ -1,4 +1,4 @@
import Database, { Database as DatabaseType } from "better-sqlite3";
import Database, { type Database as DatabaseType } from "better-sqlite3";
let dbConnection: DatabaseType;

View File

@ -98,7 +98,7 @@
"mime-types": "3.0.1",
"multer": "1.4.5-lts.2",
"normalize-strings": "1.1.1",
"ollama": "0.5.14",
"ollama": "0.5.15",
"openai": "4.97.0",
"rand-token": "1.0.1",
"safe-compare": "1.1.4",

View File

@ -4,7 +4,7 @@
TriliumNext Notes 是一个层次化的笔记应用程序,专注于建立大型个人知识库。请参阅[屏幕截图](https://triliumnext.github.io/Docs/Wiki/screenshot-tour)以快速了解:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="https://github.com/TriliumNext/Notes/blob/develop/images/screenshots/app.png?raw=true" alt="Trilium Screenshot" width="1000"></a>
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./app.png" alt="Trilium Screenshot" width="1000"></a>
## ⚠️ 为什么选择TriliumNext

View File

@ -6,7 +6,7 @@ TriliumNext Notes es una aplicación de toma de notas jerárquicas multi-platafo
Vea estas [capturas de pantalla](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) para un vistazo rápido:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="https://github.com/TriliumNext/Notes/blob/develop/images/screenshots/app.png?raw=true" alt="Trilium Screenshot" width="1000"></a>
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./app.png" alt="Trilium Screenshot" width="1000"></a>
## ⚠️ ¿Por qué usar TriliumNext?

View File

@ -6,7 +6,7 @@ TriliumNext Notes è un'applicazione per appunti ad organizzazione gerarchica, s
Vedi [fotografie](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) per una panoramica veloce:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="https://github.com/TriliumNext/Notes/blob/develop/images/screenshots/app.png?raw=true" alt="Trilium Screenshot" width="1000"></a>
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./app.png" alt="Trilium Screenshot" width="1000"></a>
## ⚠️ Perchè TriliumNext?
[Il progetto originale Trilium è in modalità di manutenzione](https://github.com/zadam/trilium/issues/4620)

View File

@ -4,7 +4,7 @@
Trilium Notes は、大規模な個人知識ベースの構築に焦点を当てた、階層型ノートアプリケーションです。概要は[スクリーンショット](https://triliumnext.github.io/Docs/Wiki/screenshot-tour)をご覧ください:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="https://github.com/TriliumNext/Notes/blob/develop/images/screenshots/app.png?raw=true" alt="Trilium Screenshot" width="1000"></a>
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./app.png" alt="Trilium Screenshot" width="1000"></a>
## 🎁 特徴

View File

@ -4,7 +4,7 @@
Trilium Notes это приложение для заметок с иерархической структурой, ориентированное на создание больших персональных баз знаний. Для быстрого ознакомления посмотрите [скриншот-тур](https://triliumnext.github.io/Docs/Wiki/screenshot-tour):
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="https://github.com/TriliumNext/Notes/blob/develop/images/screenshots/app.png?raw=true" alt="Trilium Screenshot" width="1000"></a>
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./app.png" alt="Trilium Screenshot" width="1000"></a>
## 🎁 Возможности

View File

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 174 KiB

View File

@ -9,7 +9,6 @@
"client:test": "nx test client",
"client:build": "nx build client",
"client:coverage": "nx test client --coverage",
"server:test": "nx test server",
"server:build": "nx build server",
"server:coverage": "nx test server --coverage",
@ -19,7 +18,6 @@
"chore:ci-update-nightly-version": "tsx ./scripts/update-nightly-version.ts",
"chore:update-build-info": "tsx ./scripts/update-build-info.ts",
"chore:update-version": "tsx ./scripts/update-version.ts",
"test": "pnpm nx run-many -t test",
"coverage": "pnpm nx run-many -t coverage"
},
@ -38,7 +36,6 @@
"@nx/web": "20.8.0",
"@nx/webpack": "20.8.0",
"@playwright/test": "^1.36.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
"@svgr/webpack": "^8.0.1",
"@swc-node/register": "~1.9.1",
"@swc/cli": "~0.6.0",
@ -66,7 +63,7 @@
"typescript-eslint": "^8.19.0",
"vite": "^6.0.0",
"vitest": "^3.0.0",
"webpack-cli": "^5.1.4"
"webpack-cli": "^6.0.0"
},
"license": "AGPL-3.0-only",
"author": {
@ -86,5 +83,5 @@
"axios": "^1.6.0",
"express": "^4.21.2"
},
"packageManager": "pnpm@10.9.0+sha512.0486e394640d3c1fb3c9d43d49cf92879ff74f8516959c235308f5a8f62e2e19528a65cdc2a3058f587cde71eba3d5b56327c8c33a97e4c4051ca48a10ca2d5f"
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
}

651
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -18,5 +18,6 @@ onlyBuiltDependencies:
- electron-winstaller
- fs-xattr
- macos-alias
- sqlite3
nodeLinker: isolated

View File

@ -32,6 +32,9 @@
},
{
"path": "./packages/express-partial-content"
},
{
"path": "./apps/db-compare"
}
]
}