Commit graph

2129 commits

Author SHA1 Message Date
Dan Stillman
e56fad828d Throw from removed selection methods in pre-release builds
The shims from 5697ee0af7 keep old plugins working for users, but
beta/dev/source builds should still throw to get the attention of
developers and (hopefully breakage-tolerant) beta users.
2026-09-02 22:34:19 -04:00
Dan Stillman
5697ee0af7 Shim removed selection methods when a single row is selected
Plugins written for earlier versions call methods like
CollectionTree#getSelectedSearch(), which now throw. We did this
intentionally to make old code more obviously broken, even with single
selection, so developers would fix their code, but we're not yet
blocking plugins that illegitimately declared compatibility with a
future version, so some haven't been updated and are breaking Zotero.
With a single row selected, the pre-10 functions can technically
continue to work, so for now, restore them and just warn and name the
plugin instead of throwing. They still need to throw if multiple rows
are selected, since plugins that haven't been updated can't safely act
on a selection that might span collections or libraries.

https://forums.zotero.org/discussion/133565/
2026-09-02 22:16:13 -04:00
Dan Stillman
08ed64f17f Fix "false" in Added By/Modified By columns for trashed collections
The row values were computed with `row.isItem && …`, so collection and
search rows in the trash got the boolean `false`, which the table then
rendered as the text "false".

https://forums.zotero.org/discussion/133560/
2026-09-02 12:18:12 -04:00
Dan Stillman
661843b03f Fix sync error due to invalid attachment filename
A stored-file path of 'storage:/' -- left behind by the 128 schema step,
which skipped paths with no basename -- triggered an
NS_ERROR_FILE_UNRECOGNIZED_PATH that aborted the whole
checkForUpdatedFiles() loop, so no files synced in the library. Skip an
attachment that throws instead of failing the whole library.

Also apply the setter's directory-path rule in getFilePath[Async]() to
avoid errors elsewhere.

https://forums.zotero.org/discussion/133523/synchronize-issue
2026-09-01 22:52:54 -04:00
Dan Stillman
a0ce7b3256
Show recently used collections in the Add to Collection menu (#6036)
Collections are now tracked as they're selected, added to, or dropped
on, and the five most recent usable targets are listed above the
full collection hierarchy by full path.
2026-09-01 21:59:20 -04:00
Dan Stillman
4a8a88dd41 Fix error using a CSL 0.8 style
transformToDocument() needs a load group, which it takes from the source
document or from the window that created the XSLTProcessor. Neither of
those has existed since 0f2690eb75 in Zotero 8 stopped taking
XSLTProcessor from the hidden window, so the CSL 0.8 → 1.0 upgrade threw
NS_ERROR_FAILURE. In Word, this showed as "Zotero encountered an error
while updating your document."

https://forums.zotero.org/discussion/133543/
2026-09-01 15:45:48 -04:00
Dan Stillman
984a72a3d9 Fix the startup error shown when the database can't be written to
Regression from b27c4cb023 in 10.0, which added pragma commands that
write to the database. If those failed because the database was
read-only, we would show a raw SQLite error instead of the message about
permissions.

https://forums.zotero.org/discussion/133521/error-for-zotero-10-for-mac
2026-08-31 14:23:53 -04:00
Dan Stillman
e679473db1 Remove citeproc-rs
citeproc-rs is no longer maintained, and people who had enabled the
hidden pref were hitting errors.

This also drops the free() call on CSL engines, which only existed to
free the citeproc-rs wasm driver.

https://forums.zotero.org/discussion/133515/
2026-08-31 12:38:05 -04:00
Dan Stillman
30425e024d Revoke the server API key if it can't be stored locally
The login session creates a key on the server before we try to store it,
so each attempt that failed to save the key left an active key behind.
2026-08-31 12:21:52 -04:00
Dan Stillman
ace9fa0227 Report the real cause of an OS keystore failure
Every failure shows "User canceled OS unlock entry" no matter what went
wrong. Test the store for the actual state, and give callers a message
describing what couldn't be accessed.
2026-08-31 12:21:29 -04:00
Dan Stillman
57c8c81872 Don't show credential dialogs during automatic syncs
Both the keystore fallback prompt and the migration alert are reachable
from the credential read paths that a sync uses, so don't show if it's
an automatic sync.
2026-08-31 11:55:58 -04:00
Dan Stillman
892898040b Fall back to saving credentials without OS keystore encryption
Some Linux systems have no Secret Service running, and if users can't
change that (e.g., a managed system), storing an API key fails and login
never completes. Offer to store credentials unencrypted instead, and try
to encrypt them on a later read if the keystore becomes usable.

https://forums.zotero.org/discussion/133418/
2026-08-31 11:44:43 -04:00
Dan Stillman
fa94212496 Advanced search: Use the shared find-as-you-type for the conditions menu
The conditions menu had its own find-as-you-type, which
Utilities.Internal.addMenuFindAsYouType() now provides for any menu.
Matching walks the menu rather than a cached list of every condition, so
typing can no longer select a condition the menu doesn't offer --
Collection and Saved Search are removed when the search spans multiple
libraries.

An attachment or annotation condition is shown with a short label inside
its submenu, so pass the full name to match on, which is what the
menulist shows once the condition is selected.
2026-08-28 14:16:10 -04:00
Dan Stillman
c8b841df8a Advanced search: Show subcollections in submenus
The Collection value menu was a flat list of every collection in the
library, with subcollections set apart by an indent (or hyphens before
606d8f19ba). Build it with Utilities.Internal.createMenuForTarget()
instead, using the new 'filter' feature to limit to collections. The new
FAYT helper preserves matching on subcollections.

If a subcollection is selected, open the path down to the subcollection
when opening the menu. (As of fx153, macOS renders popups as native
menus, which can't be opened to a submenu, so revert to non-native menus
there.) A collection in a submenu can't be a menulist's selected item,
so the condition holds the value and sets the menulist's label and icon
itself, with the collection's path as a tooltip.
2026-08-28 14:13:26 -04:00
Dan Stillman
c2052cfff1 Don't add items in imported collections to the import collection
Items are added to the collection created for an import as they're
saved, before the imported collection hierarchy exists, so an item only
in a subcollection ended up in the top collection as well as its own.
Remove those once the hierarchy has been created.

When everything imported belongs to a single top-level collection, that
collection is used for the import rather than being nested inside a
collection named after the file.

https://forums.zotero.org/discussion/133174/
2026-08-27 14:15:19 -04:00
Dan Stillman
61174e2158 Export selected collections as collections
Exporting a collection included only its subcollections, so an item
directly in the collection came through with no collection at all, and
an item in both the collection and a subcollection came through in only
the subcollection.

Exporting a selection of multiple collections exported a flat list of
items with no collections at all.

We now include the selected collection(s), with one exception: if a
saved search is also selected, we export a flat item list, since a
search can't be exported as a collection.
2026-08-27 14:15:19 -04:00
Dan Stillman
3b93d33b35 Fix WebDAV downloads with non-ASCII characters in the password
HTTP.download() built the Basic auth header with btoa(), which throws
on code points above 255, so every file download failed immediately
with a TypeError. Requests that go through XMLHttpRequest were
unaffected, since Necko builds the header itself, UTF-8 encoded.

https://forums.zotero.org/discussion/133454/synchronization-error-after-upgrading-to-10-0-1
2026-08-27 10:46:00 -04:00
Dan Stillman
0c9ba2d05c Fix corruption of non-ASCII characters in encrypted credentials
Mozilla's OSKeyStore.encrypt() encodes the string as UTF-8 before
encrypting, but its decrypt() returns the decrypted bytes as a binary
string without decoding them, so a WebDAV password containing non-ASCII
characters came back mojibake and authentication failed.

https://forums.zotero.org/discussion/133465/problem-login-into-webdav-server-with-10-0-1
2026-08-27 10:45:45 -04:00
Dan Stillman
ff93139cce Localize the search syntax's operators and other words
Some checks are pending
CI / Detect changes (push) Waiting to run
CI / Build, Upload (push) Waiting to run
CI / Test () (push) Blocked by required conditions
CI / Test (macOS NFS) (push) Blocked by required conditions
CI / Test (Windows arm64) (push) Blocked by required conditions
CI / Test (Windows x64) (push) Blocked by required conditions
CI / Utilities Tests (push) Waiting to run
Operators can be typed as the Advanced Search shows them, which every
locale already translates, and new keyword messages cover the join
words, "no"/"has", the units of a relative date, and the range forms.

Each range form is given as an example with its two ends filled in, so
that a locale can say it its own way and each form keeps its own words
(e.g., no "between 1970 to 2000").
2026-08-26 15:19:44 -04:00
Dan Stillman
4a250cd20f Support date and count ranges in the search syntax
"year is between 1970 and 2000", "year:1970-2000", "1970..2000", and
"1970 to 2000" all match values within the range, inclusive of both
ends. Ends can be a year, a month ("added between 2024-02 and
2024-06"), a day ("date:2020-03-01..2020-03-15"), or a count ("number
of tags between 2 and 5").
2026-08-26 15:17:55 -04:00
Mynacol
d153397151
Use versioned libc.so instead of /bin/ln on Linux (#6030)
* Fix js-ctypes-based symlinking on Linux by using `libc.so.6` instead of `libc.so` in `OS.File.unixSymlink()` and `Zotero.File.createSymlink()`
* Use that instead of `/bin/ln`, which doesn't exist on NixOS
* Replace `/bin/ln` with `Zotero.File.createSymlink()` in symlinked-database test

---------

Co-authored-by: Dan Stillman <dstillman@zotero.org>
2026-08-26 13:02:48 -04:00
Dan Stillman
5d20c692e8 Don't use FSEvents when storage isn't on a local volume
FSEvents is backed by a per-volume journal that only local volumes
have. On a network mount the stream is created and started
successfully but never delivers events, so the watcher would report
that nothing had changed for as long as it was used. Check the volume
with statfs() and fall back to scanning.
2026-08-26 10:36:54 -04:00
Dan Stillman
a1ea7037c2 Fix locally missing attachments never being downloaded
Since f21e1b2d32, a full local file scan no longer runs periodically and
on every manual sync, so locally missed attachments stayed marked for
upload and were skipped as unavailable instead of being downloaded.
"Reset File Sync History" marked every attachment for upload, including
files that had never been downloaded, so the forced download check added
in 404fc41b88 found nothing to download.

Missing files are now marked for download when the upload queue is
filled, and in at-sync-time mode they're downloaded in the same sync.
The reset marks them for download directly, and downloads are no longer
skipped just because there were no remote storage changes.

https://forums.zotero.org/discussion/133414/
2026-08-26 10:36:54 -04:00
Adomas Venčkauskas
baa47e3bb9 Remove bibliography when last citation is deleted. Closes #3474 2026-08-25 15:55:11 +03:00
Dan Stillman
f2a42bec15 Retry note saves that time out waiting for the database
Some checks are pending
CI / Detect changes (push) Waiting to run
CI / Test () (push) Blocked by required conditions
CI / Test (macOS NFS) (push) Blocked by required conditions
CI / Test (Windows arm64) (push) Blocked by required conditions
CI / Test (Windows x64) (push) Blocked by required conditions
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
Any error while saving a note prompted the user to restart Zotero, even
a transaction timeout caused by a long-running operation elsewhere.
Nothing has been written when the wait times out, so retry, unless newer
note content has been handed to the editor in the meantime.

https://forums.zotero.org/discussion/133298/
2026-08-21 16:31:18 -04:00
Dan Stillman
070ae8b615 Don't hold the database to optimize the full-text index
Editing a note flagged it stale, and the background drain indexed it and
then ran an FTS5 'optimize' -- a single statement that rewrites the
content index and can hold the shared database for over a minute --
because the queue was empty again. Note saves waiting on the connection
hit the transaction timeout and told the user to restart Zotero.

Merge the index in bounded steps instead, so no statement runs long
enough to keep other queries waiting, and only after enough items have
been indexed to be worth it.

https://forums.zotero.org/discussion/133298/
2026-08-21 16:31:18 -04:00
Dan Stillman
ad98e84d24 Fix Any Field searches at a non-item result level
Any Field expands to a generic 'field' condition, which the cross-level
code treated as matching only on top-level items. At an attachment
result level it therefore matched attachments whose parent item had the
value, instead of attachments with the value themselves. Since the
condition stands in for every field, it's now treated as matching at any
level those fields live at.
2026-08-21 12:56:05 -04:00
Dan Stillman
77a3a8815e Add a query syntax to the quick search
Some checks are pending
CI / Detect changes (push) Waiting to run
CI / Test () (push) Blocked by required conditions
CI / Test (macOS NFS) (push) Blocked by required conditions
CI / Test (Windows arm64) (push) Blocked by required conditions
CI / Test (Windows x64) (push) Blocked by required conditions
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
Zotero.SearchQuery turns a query like `by:smith after:2020 tag:"to read"
crispr` or `creator is smith and (tag is foo or bar)` into a
Zotero.Search, matching whatever text is left over using the current
search mode. Anything that doesn't look like a clause is free text, so a
DOI or a title with a colon in it is matched literally.

The search box syntax-highlights the parts of recognized conditions and
offers autocomplete for condition names, for the values of conditions
that have a fixed set of them (like item type), and for tags and
creators from the selected libraries.
2026-08-20 16:09:20 -04:00
Dan Stillman
0ee3e4052e Don't prompt to save an unchanged saved search
https://forums.zotero.org/discussion/133302/zotero-10-questions-about-search
2026-08-20 15:38:13 -04:00
Dan Stillman
0746c665a9 Don't match dates without a sortable year in "is before" searches
Values without a parsable year are stored with a 0000-00-00 sort key,
and the guard meant to exclude them from comparisons checked the full
multipart value, which is always greater than '0000-00-00'.
2026-08-20 13:19:23 -04:00
Dan Stillman
73f4273e2d Make Original Date a date field
Update the global schema to 45, resolve a field's date type through its
base-field mapping in ItemFields.isDate() (to cover priorityDate), and
convert stored values of date-type fields to multipart dates on schema
upgrade.
2026-08-20 12:57:46 -04:00
Dan Stillman
04796dff22 Use date operators for all date-type item fields in searches
Only Date and Accessed were routed to the datefield condition, so other
date fields (e.g., Filing Date) offered only text operators and
couldn't be compared as dates. Text operators are still accepted on
date fields so existing saved searches keep loading and running.
2026-08-20 12:57:46 -04:00
Dan Stillman
c220866d9a Use a platform-appropriate path in file access error test
The hardcoded POSIX path isn't valid on Windows.
2026-08-20 12:34:41 -04:00
Dan Stillman
cdb13af13b Wait for the browser process in Windows test runs
zotero.exe is the Mozilla launcher process, which spawns the browser
process and exits, so the test runner checked for the success file and
cleaned up the profile while the app was still starting, and passing
runs were reported as failures that ended at arbitrary points.
2026-08-20 12:34:41 -04:00
Dan Stillman
32640e2019 Wait for test success file to be written before quitting
The write is asynchronous, and on Windows the app quit before it
finished, making passing test runs report failure.
2026-08-20 12:34:40 -04:00
Dan Stillman
dac1ad489f Update utilities submodule
Some checks are pending
CI / Detect changes (push) Waiting to run
CI / Test () (push) Blocked by required conditions
CI / Test (macOS NFS) (push) Blocked by required conditions
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
And add test for citing date strings wrapped in double quotes

https://forums.zotero.org/discussion/133277/
2026-08-19 15:28:34 -04:00
Dan Stillman
4e532a17a2 Skip symlink tests on filesystems without symlink support
CIFS mounts can't create real symlinks without special mount options,
so skip the symlinked-database and broken-symlink tests when a created
symlink doesn't exist or isn't visible as one.
2026-08-19 09:37:38 -04:00
Dan Stillman
bba85a3939 Fix database access on network filesystems on macOS and Linux
On macOS, SQLite chooses locking methods based on the filesystem
containing the database, and network filesystems (e.g., SMB, NFS),
read-only volumes, and filesystems without byte-range locking get
methods without shared-memory support, which WAL requires. Opening a
database with an adjacent WAL file on those crashes -- Mozilla's VFS
wrapper hides the missing shared-memory methods from SQLite's WAL
support check -- so the first Zotero 10 run converted the database to
WAL and every launch after that segfaulted during connection
initialization.

On macOS, mirror SQLite's method selection and use a rollback journal
when shared memory isn't available, converting an existing WAL database
before opening it: an empty WAL by reverting the header format versions
in place, and a non-empty WAL by replaying it into a temporary copy on
local disk that replaces the database file only after passing an
integrity check. A WAL file next to an already-converted database
(e.g., from an interrupted conversion) goes through the same
conversion. Also use openNotExclusive during integrity checks and
corruption recovery, which otherwise fail on SMB shares with an I/O
error from the exclusive open lock.

This corrects 22055d92b7, which passed openNotExclusive on all
platforms for an open failure described as affecting macOS and Linux,
and expected locking_mode=EXCLUSIVE to keep the WAL index in heap
memory with no -shm file. Neither claim held up: mozStorage opens the
WAL while initializing the connection, before any pragma can run, so
the index uses shared memory unless the exclusive VFS is in use, and
the exclusive open works on Linux CIFS mounts -- where non-exclusive
access instead made SQLite's lock-upgrade sequence trip over the SMB
byte-range lock mapping, leaving startup hung and the database never
created. So pass openNotExclusive only on macOS. On Linux this restores
unix-excl, which performs all locking under a single held lock and
keeps the WAL index in heap memory; Windows has no distinct exclusive
VFS and is unaffected.

https://forums.zotero.org/discussion/133258/
2026-08-18 14:38:37 -04:00
Maximilian Schmidt
b8fdee865a
Fix zero local data object versions (#6016)
Some checks are pending
CI / Test (shard 1) (push) Waiting to run
CI / Test (shard 2) (push) Waiting to run
CI / Test (shard 3) (push) Waiting to run
CI / Test (shard 4) (push) Waiting to run
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
2026-08-13 11:23:05 -04:00
Dan Stillman
29a4d9d140 Skip focus traversal tests when the pane window can't be activated
The traversal waits on focus/blur events, which Gecko fires only while
the window is active, so a window that can't be activated -- another
app focused during a local run, or intermittent deactivation in CI --
timed out after 10 seconds instead of reporting that it couldn't run.
2026-08-13 10:43:51 -04:00
Dan Stillman
472a0bf856 Update utilities submodule
And add a test for citing a spelled-out BCE date, which citeproc-js
rendered as AD.
2026-08-13 10:01:09 -04:00
Tom Najdek
68bec97114
Add support for importing from encrypted Mendeley Desktop DB (#6019) 2026-08-13 09:33:41 -04:00
Dan Stillman
8d01216e5c Fix flaky search tests that used common words
Tests asserted exact search results for words like "one" and "two", so
a leftover item from an earlier test whose random title contained one
of the words as a substring could match and fail the assertion. Use
distinctive random strings instead.
2026-08-12 14:24:22 -04:00
Dan Stillman
8ac1273acb Support citing EDTF dates in the Date field and Extra
EDTF dates -- ranges ("2021/2026"), uncertain/approximate dates
("2004-06~"), and BCE dates ("-0429") -- and common equivalent notations
("1995-1996", "2021-22", "~1995", "ca. 1995", "429 BCE") are now passed
to citeproc-js as CSL date ranges, circa flags, and negative years.
Previously, such dates were mangled or dropped entirely unless entered as
CSL variables in Extra.

CSL date variables in Extra get the same parsing.

Other date handling in the client doesn't understand EDTF yet: the y/m/d
indicator in the date field doesn't reflect EDTF parsing, date searches
only match a range by its start date, and BCE dates still can't be
sorted.

Addresses #637
2026-08-12 14:11:26 -04:00
Adomas Venčkauskas
e5508e870c Actually return 400 and throw when multipart body is malformed.
Some checks are pending
CI / Test (shard 1) (push) Waiting to run
CI / Test (shard 2) (push) Waiting to run
CI / Test (shard 3) (push) Waiting to run
CI / Test (shard 4) (push) Waiting to run
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
Closes #6009
2026-08-10 16:16:00 +03:00
Dan Stillman
c1cdd038a2 Select item explicitly in item-pane refresh test
The test relied on the automatic selection of a newly created item,
which can lose the race with a view switch (e.g., from another library
selected by a previous test), leaving the info pane empty.
2026-08-09 22:09:02 -04:00
Dan Stillman
fe35127f50 Update items-in-view count when rows change without a selection
Notifier events that added or removed rows (e.g., items downloaded
during a sync) didn't update the no-selection message in the item pane,
so the count went stale until the selection changed. The row provider
now emits a rowCountChange event, and the pane re-renders the count,
debounced, when nothing is selected.
2026-08-09 14:49:21 -04:00
Dan Stillman
04321fc627 Restore cached user name on transaction rollback
Zotero.Users.setName() updated the in-memory cache even if the
transaction was later rolled back, so a retry (e.g., of a failed sync
download batch) would skip rewriting the users row.
2026-08-09 14:29:48 -04:00
Dan Stillman
646fbfae65 Don't treat error in commit callback as a rollback
An error thrown from a commit callback rejected executeTransaction()
even though the transaction had been committed, so callers would treat
saved data as rolled back, and rollback callbacks (e.g., the notifier
reset) ran against committed data. Commit-callback errors are now
logged instead, and any error after a successful commit skips rollback
callbacks and is marked with 'committed' on the error object.
2026-08-09 14:22:21 -04:00
Dan Stillman
46603ca4eb Discard queued commit callbacks on transaction rollback
If a transaction was rolled back, callbacks queued via
addCurrentCallback('commit') stayed queued and ran after the next
successful commit, potentially applying in-memory cache updates for
rolled-back data.
2026-08-09 14:22:20 -04:00