Commit Graph

37763 Commits

Author SHA1 Message Date
renovate[bot]
d5a3550b71
Update pnpm to v12.4.0 2026-09-12 00:22:52 +00:00
Elian Doran
0f1f569f7a
docs(user): update quick search
Some checks are pending
Checks / main (push) Waiting to run
CodeQL Advanced / Analyze (${{ matrix.language }}) (none, actions) (push) Waiting to run
CodeQL Advanced / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Waiting to run
Deploy Standalone App / Build and Deploy App (push) Waiting to run
Deploy Documentation / Build and Deploy Documentation (push) Waiting to run
Dev / Detect affected suites (push) Waiting to run
Dev / Test development (push) Waiting to run
Dev / Test server (push) Blocked by required conditions
Dev / Test standalone (push) Blocked by required conditions
Dev / Test CKEditor 5 (shard ${{ matrix.shard }}) (1) (push) Blocked by required conditions
Dev / Test CKEditor 5 (shard ${{ matrix.shard }}) (2) (push) Blocked by required conditions
Dev / CKEditor 5 coverage gate (push) Blocked by required conditions
Dev / Build Docker image (push) Waiting to run
Dev / Check Docker build (Dockerfile) (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile.alpine) (push) Blocked by required conditions
/ Check Docker build (Dockerfile) (push) Waiting to run
/ Check Docker build (Dockerfile.alpine) (push) Waiting to run
/ Build Docker images (Dockerfile, ubuntu-24.04-arm, linux/arm64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.alpine, ubuntu-latest, linux/amd64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v7) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v8) (push) Blocked by required conditions
/ Merge manifest lists (push) Blocked by required conditions
playwright / E2E tests on ${{ matrix.name }} (arm64, linux-arm64, ubuntu-24.04-arm) (push) Waiting to run
playwright / E2E tests on ${{ matrix.name }} (x64, linux-x64, ubuntu-22.04) (push) Waiting to run
playwright / PDF viewer E2E tests (push) Waiting to run
playwright / Standalone E2E tests on ${{ matrix.name }} (linux-arm64, ubuntu-24.04-arm) (push) Waiting to run
playwright / Standalone E2E tests on ${{ matrix.name }} (linux-x64, ubuntu-22.04) (push) Waiting to run
2026-09-11 23:26:15 +02:00
Elian Doran
d595fb33e8
docs(claude): record the core API tester's header-seeded context
CoreApiTester now seeds the execution context from the trilium-* request
headers, so Pattern 0 documents how to drive a hoisted request and warns that
a spec omitting trilium-hoisted-note-id exercises the unhoisted path. Anything
reading hoistedNoteService.getHoistedNoteId() — quick search, autocomplete,
SearchContext's implicit ancestorNoteId — sees "root" without it, so a passing
spec is not evidence that scoping works. A contributor's quick-search PR
asserted exactly that and proved nothing.

The Windows note covered only `pnpm --filter … exec vitest`; the auto-install
fires for a package's own test script too. It now names the symptom seen here:
EPERM / Access is denied on a node_modules directory VS Code holds open, which
rolls back cleanly but loses the run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 23:26:08 +02:00
Elian Doran
cd381e09fe
fix(search): keep result paths out of the bookmarks clone (closes #10021)
Bookmarking a note clones it under `_lbBookmarks`, so every descendant gains a
second note path running through `_hidden`. Searching creates an ad-hoc search
note under `_hidden/_search` and activates it. Result cards address their target
by bare note id and leave the path to the client, and `getSortedNotePathRecords`
compared the active note's path prefix before every other criterion. The real
path shares only `root` with the active search note while the bookmark clone
shares `root/_hidden`, so two segments beat one and the hidden check below never
ran. The card opened the note under Bookmarks, and in grid view the breadcrumb
said so too.

The tiebreaker comes from #7552, where it picks the nearest clone so that
opening a note keeps the user in the subtree they came from. Every candidate
there is an ordinary clone, so ranking it below the hoisted, archived, hidden
and search comparisons preserves that and only stops it from overruling them.

The server was never wrong here: `compareNotePathRecords` ranks hidden paths
last and takes no active path. The client threw that answer away and re-derived
the path from froca.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 23:21:23 +02:00
Elian Doran
7edff12d9b
fix(search): confine quick search to the hoisted subtree (closes #10803)
Quick search widened its scope to the whole tree whenever the hoisted note
lived inside _hidden, so browsing the in-app help returned the user's own
notes instead of help pages. It also passed includeHiddenNotes, which made an
unhoisted quick search return notes that have no visible path at all.

Neither setting was chosen for quick search. Both arrived together in
8e227a6146, a commit about highlighting exact matches, which copied the
search context of searchNotesForAutocomplete verbatim into the quickSearch
route.

The widening belongs to autocomplete alone. It was added in 6a9ac6f90a for
the launcher work: while hoisted into the hidden configuration area, the
note-link autocomplete still has to reach normal notes so a launcher can
point at one. It first sat in the SearchContext constructor, where it applied
to every search that passed no explicit ancestor, and 88bc7402a2 deliberately
narrowed it to the one function that needs it, introducing includeHiddenNotes
and the IsHiddenExp filter at the same time. That commit's subject states the
intent this one restores: hidden notes should not appear in the global search
unless hoisted into it.

Quick search now scopes to the hoisted note with no special case, so a hoist
into the hidden subtree confines it there like any other hoist. The two
settings have to move together: getAncestorExp only applies the hidden filter
when the ancestor is root, so dropping includeHiddenNotes while keeping the
widening would leave a hoist into help searching everything except help.

Hoisting to _hidden itself now yields nothing, because getSubtree defaults to
includeHidden: false and stops at that node. Hidden descendants, help and the
launcher bar included, traverse normally. Letting AncestorExp traverse hidden
notes would fix that, but the expression also backs saved searches and ETAPI
queries, so it is left for a separate change.

CoreApiTester never seeded the execution context from request headers, so no
spec could describe a hoisted request; the route read "root" whatever the
spec did. It now seeds hoistedNoteId, componentId and localNowDateTime from
the trilium-* headers, matching route_api.ts on Express and browser_routes.ts
in standalone. The new specs create their hidden note under _lbBookmarks
because the API refuses children directly under _hidden and _help*.

The comment in SearchContext explaining the widening has documented a
condition that no longer exists since 88bc7402a2 and is removed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 23:12:56 +02:00
Elian Doran
73edb95583
fix(text editor): handle Enter on collapsed list items (closes #11256) (#11335) 2026-09-11 22:27:02 +02:00
Elian Doran
843777e6e1
refactor(code): remove the unused editor background plumbing
The previous commit stopped painting the scrolling container with
`--code-background-color`, which leaves nothing in the tree that reads
the variable. Everything that produced it is therefore dead:

- `CodeEditor` wrote the custom property onto the closest
  `.scrolling-container` from a `backgroundColor` state, fed by a
  callback chained onto `setTheme`. That callback ran
  `getComputedStyle` against the `.cm-editor` on every theme change, so
  dropping it also drops a forced style read per switch.
- `noBackgroundChange` existed only to suppress that write for embedded
  editors, and `SplitEditor` was its only caller. `CodeEditorProps` held
  nothing else, so it goes with it; the `Omit<CodeEditorProps,
  "onContentChanged">` on `EditableCodeProps` never omitted anything,
  since that interface declares its own `onContentChanged`.
- `parentComponent` reached `CodeEditor` only to find the scrolling
  container, so it comes off the props type and off the three call
  sites in `ReadOnlyCode`, `EditableCode` and `BackendLog`.
  `EditableCode` keeps its own, which it uses for `triggerCommand` and
  `useKeyboardShortcuts`.

Also moves the corner-rounding rule below the region comments in
`code.css`. It targets both `.note-detail-code` and
`.note-detail-readonly-code`, so sitting inside `#region Editable code`
described only half of what it does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 22:22:47 +02:00
Elian Doran
a2072477f0
fix(code): light/dark combinations affect note list (closes #11309) 2026-09-11 22:11:25 +02:00
Elian Doran
3cd1b91486
TOTP: accept each code only once, and one time step of clock drift (#11448) 2026-09-11 21:57:57 +02:00
Adorian Doran
dc08b2f96e
Board improvements & app-wide icon alignment improvements (#11449) 2026-09-11 22:46:03 +03:00
Adorian Doran
60e9526802 client/collections/board: fix an issue 2026-09-11 22:24:08 +03:00
Adorian Doran
2dc25cc749 client/collections/board: improve comments 2026-09-11 22:11:49 +03:00
Adorian Doran
da088772f4 client/collections/board: allow quick drop gesture for collapsed cards too 2026-09-11 22:08:10 +03:00
Adorian Doran
1f3e72fdf0 client/collections/board: tweak the drop hint 2026-09-11 21:56:45 +03:00
Adorian Doran
c569934de2 client: fix some issues 2026-09-11 20:49:04 +03:00
Adorian Doran
eb9fd98d03 client/ui/context menu: tweak card context menu 2026-09-11 20:00:07 +03:00
Adorian Doran
56dad66adc client/ui/context menu: fix menu item label spacing issue 2026-09-11 19:45:29 +03:00
Adorian Doran
bb4c793a88 update pnpm-lock 2026-09-11 19:36:56 +03:00
Adorian Doran
e64f5a9b7f client/collections/board: tweak icon alignment 2026-09-11 19:35:04 +03:00
Elian Doran
562e75bcd4
fix(ci): unbreak the Windows nightly and release builds (#11450) 2026-09-11 17:55:50 +02:00
Elian Doran
40484a799c
Translations update from Hosted Weblate (#11446) 2026-09-11 17:50:27 +02:00
Elian Doran
c7a90de303
Update dependency marked to v18.0.12 (#11441) 2026-09-11 17:49:19 +02:00
Giovi
0ec9981ffc
Translated using Weblate (Italian)
Currently translated at 100.0% (156 of 156 strings)

Translation: Trilium Notes/Entrypoints (first setup, login, set password)
Translate-URL: https://hosted.weblate.org/projects/trilium/entry/it/
2026-09-11 17:49:13 +02:00
Artyom Rybakov
2f549c97cf
Translated using Weblate (Russian)
Currently translated at 100.0% (132 of 132 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ru/
2026-09-11 17:49:13 +02:00
Giovi
9adde1c2a7
Translated using Weblate (Italian)
Currently translated at 100.0% (132 of 132 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/it/
2026-09-11 17:49:13 +02:00
Giovi
1f15a9d194
Translated using Weblate (Italian)
Currently translated at 100.0% (459 of 459 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/it/
2026-09-11 17:49:13 +02:00
Giovi
9129a5cba2
Translated using Weblate (Italian)
Currently translated at 99.9% (3517 of 3519 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2026-09-11 17:49:13 +02:00
Artyom Rybakov
b581c7c6f4
Translated using Weblate (Russian)
Currently translated at 85.8% (3022 of 3519 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ru/
2026-09-11 17:49:13 +02:00
윤남혁
487ff4750f
Translated using Weblate (Korean)
Currently translated at 100.0% (3519 of 3519 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ko/
2026-09-11 17:49:13 +02:00
green
6cb068fe05
Translated using Weblate (Japanese)
Currently translated at 100.0% (3519 of 3519 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2026-09-11 17:49:13 +02:00
小三月
d423751617
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (3519 of 3519 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2026-09-11 17:49:13 +02:00
Elian Doran
4572ca8e7b
Update dependency node-html-parser to v9.0.4 (#11442) 2026-09-11 17:49:02 +02:00
Elian Doran
692ad25738
Update dependency maplibre-gl to v6.8.0 (#11443) 2026-09-11 17:48:30 +02:00
Elian Doran
af7a23c588
Update dependency typescript-eslint to v8.70.0 (#11444) 2026-09-11 17:47:51 +02:00
Elian Doran
3ec854f967
fix(ci): give the release build the same shell as the nightly
make-electron runs on the same win-signing runner, where `pnpm` invoked from
PowerShell under pnpm/action-setup's pnpm 12 bootstrap exits 0 without
installing anything. The job has not run since that bootstrap landed, the
last release being v0.105.0 on Aug 19, so the next tag push would have hit
what the nightly hit.

Unlike the nightly this job never rewrites the workspace versions, so it
never triggered the implicit re-install that was covering for the dead
install step, and setup-node already caches its store. The shell is the only
part it needs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 17:46:27 +02:00
Adorian Doran
02cf0a116a icon pack builder: measure glyphs when building an icon pack, use the metrics to create a more visually accurate vertical alignment for icons 2026-09-11 18:45:38 +03:00
Elian Doran
7b3e2bdeec
fix(ci): run the nightly's pnpm steps through the platform's own shell
Under pnpm/action-setup 6.1.0's pnpm 12 bootstrap, `pnpm` invoked from
PowerShell on the win-signing runner writes nothing and exits 0 without
installing anything. The same command under cmd works, which is why the
build step's implicit re-install was the only install the Windows jobs had
been getting since that bump, and why "Update nightly version" has been
leaving the version field untouched there.

So the previous commit removed the install that was actually running, and
the build failed on `'tsx' is not recognized`. Take the job's default shell
from the matrix, so the two job-level pnpm steps use cmd on Windows and bash
elsewhere, matching what build-electron already does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 17:30:58 +02:00
Elian Doran
d6f6a9afa0
fix(ci): keep the nightly's pnpm store off the runner's pnpm install
The two Windows nightly jobs share one persistent win-signing runner, and
both re-download the whole dependency tree from npm on every run, twice.
That download is what fails: a tarball fetch timeout on Sep 9, hundreds of
connection resets on Sep 10, and a store import error against a half-written
store on Sep 11, after which the arm64 job built against the incomplete tree
and share-theme's esbuild step reported 43 missing files.

pnpm derives its store from PNPM_HOME, which pnpm/action-setup points at
<dest>/node_modules/.bin, so the store sits inside the directory the action
reinstalls on every run and starts empty. The last green run reports
"reused 0, downloaded 2284"; the Sep 11 failure reports "reused 269".
Pin the store to C:\pnpm-store on Windows so it survives between jobs, and
copy packages out of it rather than hardlinking, because the better-sqlite3
rebuild and electron-forge's pruning both write into node_modules.

"Update nightly version" rewrites the version field of six workspace
manifests, so the next `pnpm run` re-installs the whole workspace before
running the script it was asked for. That second install shows up under
`chore:update-build-info` in every Windows job, the green one included. The
dependency graph is unchanged and `pnpm install --frozen-lockfile` has
already run, so turn the check off for the job.

The npm_config_package_import_method this replaces never applied: pnpm 12
reads PNPM_CONFIG_*, not npm_config_*.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 17:19:55 +02:00
Adorian Doran
ae6eb1e61a client/collections/board: style tweaks 2026-09-11 17:49:09 +03:00
Adorian Doran
5bccc1e121 client/collections/board: add outline integration 2026-09-11 17:45:29 +03:00
Adorian Doran
3fba2c2088 client/collections/board: add a quick gesture to drop a card at the top/bottom of a column 2026-09-11 17:32:48 +03:00
Adorian Doran
62abca0e2d client/collections/board: add an option to adjust the width of the columns 2026-09-11 16:53:30 +03:00
Adorian Doran
402a827091 client/collections/board: prevent a column to be renamed if that name is already used by another column 2026-09-11 16:39:47 +03:00
José M. Requena Plens
2f7a388fa2
fix(totp): skip time steps already used when matching a code
A six-digit code can repeat between adjacent time steps. findTimeStep
returned the first step that matched, so when a fresh code for the
current step was also the code of the previous step, and that step had
already been used, verifyTOTP took the fresh code for a replay and the
user had to wait for the next one.

findTimeStep now starts after the last used step, so a code is only
matched against the steps it can still be used for. A replay is still
refused: the step a used code was accepted for is no longer tried, and
the code only passes if it is also the code of a later step, where it is
as valid as any other code for that step.

A stored value that is missing, empty or not a number counts as no step
used, as before.
2026-09-11 10:09:57 +02:00
José M. Requena Plens
0e43d33744
fix(totp): accept a code from the adjacent time step
findTimeStep only tried the server's current 30-second step, as
Totp.validate without a drift option did before it. A code generated one
step earlier or later is rejected with {"success":false} and nothing in
the log, so a phone clock a few seconds off, or a code typed in the last
seconds of its step, fails enrollment and login with no way to tell why.

findTimeStep now takes how many steps on either side of the current one
also match, and enrollment and login pass CLOCK_DRIFT_STEPS, which is 1.
RFC 6238 allows for this: section 6 recommends a limit on how many steps
a client can be "out of synch", which "can be set both forward and
backward from the calculated time step", and section 5.2 recommends
"that at most one time step is allowed as the network delay". Enrollment
and login share the window, so a user cannot enroll with a code that
login would then reject.

At login a code now matches for up to 90 seconds instead of 30. The
previous commit keeps that from widening replay: verifyTOTP refuses a
used code for as long as it still matches, and any code from an earlier
step once a later one has been used. The new assertions in the
verifyTOTP test cover both.

The setup wizard's check, validateTOTP, records nothing, so it stays on
the current step: a wider window there would keep a code usable for 90
seconds instead of 30.

Login sits behind the existing limiter of 10 failed attempts per IP per
15 minutes, so accepting three codes instead of one leaves a blind guess
at about 30 in a million per 15-minute window.
2026-09-11 03:38:56 +02:00
José M. Requena Plens
0b005d40ff
fix(totp): accept each code only once at login
A TOTP code that had just been used to log in stayed valid for the rest
of its 30-second step, so the same code could be sent again and be
accepted a second time. RFC 6238, section 5.2, rules that out: "The
verifier MUST NOT accept the second attempt of the OTP after the
successful validation has been issued for the first OTP, which ensures
one-time only use of an OTP."

Totp.validate from time2fa only answers yes or no, so findTimeStep
checks the step with Hotp.validate and returns the step that matched.
The login check, verifyTOTP, records that step in totpLastUsedStep and
refuses any code from the same or an earlier step. Both callers of
verifyLoginCredentials use it: the login form, and the token handler
behind /api/login/token and /api/sender/login. The password is checked
first, so a step is only recorded once the password has matched, as
with recovery codes. setSecret clears the recorded step, so a newly
enrolled secret's first code is not refused over a step the previous
secret used.

totpLastUsedStep is local to the instance, like the TOTP secret, and
the options API neither returns nor accepts it: it is not in
ALLOWED_OPTIONS. Reading, comparing and writing it happen in one
synchronous call, so two requests carrying the same code cannot both
pass.

validateTOTP keeps checking without recording anything, for the setup
wizard. The wizard runs with becca unloaded, where options must not be
written (see SetupSecondFactor.verify), which is also why
matchesRecoveryCode leaves a recovery code unspent there. Enrollment
records nothing either: the secret is not persisted yet when
validateTOTPForSecret checks the code.
2026-09-11 03:34:11 +02:00
renovate[bot]
3338533b86
Update dependency typescript-eslint to v8.70.0 2026-09-11 00:01:41 +00:00
renovate[bot]
dccb5fe595
Update dependency maplibre-gl to v6.8.0 2026-09-11 00:01:26 +00:00
renovate[bot]
d92027b8a4
Update dependency node-html-parser to v9.0.4 2026-09-11 00:01:11 +00:00
renovate[bot]
e162644522
Update dependency marked to v18.0.12 2026-09-11 00:00:58 +00:00