Commit Graph

12326 Commits

Author SHA1 Message Date
Abdo
1d13ffe8ee Ensure PyQt base Flatpak app is installed 2026-06-25 16:45:55 +03:00
Abdo
1ea391ada0 Fix .tar suffix added to Flatpak output 2026-06-25 16:25:08 +03:00
Abdo
af838f474f Update release workflow 2026-06-25 16:24:19 +03:00
Abdo
676bc6495e Update template 2026-06-25 15:51:08 +03:00
Abdo
e06612f2f0 Use Qt 6.10 on Flatpak
The org.kde.Platform Flatpak runtime doesn't support 6.11 yet.
2026-06-25 15:34:10 +03:00
Abdo
d4befc37e4 Enable Flatpak build via an env var 2026-06-25 15:30:24 +03:00
Abdo
a7b1119f05 Remove skip_fcitx arg 2026-06-25 15:21:40 +03:00
Abdo
794a55bf91 Generate scaled icons 2026-06-25 14:37:14 +03:00
Abdo
23393f1ee7 Keep packaging metadata in the bundle
Required for Flatpak as pip install is run later.
2026-06-25 13:20:55 +03:00
Abdo
ef789aaaee Set up Flatpak support 2026-06-24 18:41:32 +03:00
Abdo
3b50783d82 chore: Bump complexipy (#5058)
For a Windows fix: https://github.com/rohaquinlop/complexipy/pull/177
2026-06-23 17:19:15 +03:00
Fernando Lins
d8ce60c272 test: add service-layer unit tests for scheduler and cards (#4924) (#5042)
## Linked issue

Fixes #4924

## Summary/motivation

The scheduler/cards service layer that the front-end and gRPC clients
call into was largely untested.

This PR adds unit tests that exercise each method through the
`SchedulerService` / `CardsService` traits (proto-in / proto-out),
mirroring how users actually use them, and asserts the resulting state
in `Collection` storage.

**Out of scope**: pure FSRS math methods are intentionally left out.

## How to test
### Details

- `cargo test -p anki --lib scheduler::service::tests` — 42 passing.
- `cargo test -p anki --lib card::service::tests` — 1 passing.
- `cargo fmt --check` and lints clean.
- Tests are deterministic and isolated (each builds its own in-memory
`Collection`); the randomize test uses a retry loop with a permutation
invariant instead of a probabilistic assertion.
2026-06-23 11:07:29 -03:00
Abdo
7188bf3056 fix: Do not block install if registry points to a deleted old elevated install (#5054)
## Linked issue

Closes #5053

## Summary

The MSI installer checks for old elevated installs (pre-2.1.64) via the
Windows registry and asks the user to manually uninstall the old version
(as it requires elevation). There are however cases where the registry
value exists but the path is missing (e.g. if the user manually removes
the Anki folder without running uninstall.exe). This makes it so that
uninstall.exe is confirmed to exist in the folder.

Template change:
8d2756a03a

## How to reproduce (before)

1. Install Anki
[2.1.63](https://github.com/ankitects/anki/releases/tag/2.1.63)
2. Go to the installation folder and delete all files
3. Try to install 26.05 and confirm installation is blocked with the
message: "A previous Anki version needs to be uninstalled first. After
uninstallation completes, please run this installer again."


## How to test (after)

Repeat the same process but with an MSI installer built from this PR and
confirm you're not blocked from installation.
2026-06-23 09:58:01 +03:00
roostwp07
f57996576f test(pylib): add hook system tests (closes #4931) (#5023)
Closes #4931

## Summary
- Adds `pylib/tests/test_hooks.py` with full behavioral coverage of
`pylib/anki/hooks.py`
- Coverage increased from 35% → 100% (issue target was 80%)
- Tests cover: hook registration/firing, `runFilter` chaining,
`remHook`, exception propagation, and `wrap` (before/after/around)

## How to test
```
just test-py --coverage
```

---------

Co-authored-by: Fernando Lins <1887601+fernandolins@users.noreply.github.com>
2026-06-22 21:08:31 +03:00
Abdo
22f90814e3 Add translation support for docs website (#5052)
## Linked issue

Closes #5004

## Summary

This adds intro entries for languages that have manual translations
listed under https://docs.ankiweb.net/#translations
Only placeholder pages with links to the contributor websites for now.


## How to test

Run `mint dev` under docs-site and try switching the language from the
top left.
2026-06-22 18:54:01 +03:00
Luc Mcgrady
9a63b95230 Fix: text input refocues when list item shortcuts are pressed (#5007)
<!--
Title (for the Pull Request title field at the top):
Use a short prefix so the change type is obvious. You do not need to
repeat it in the body below.

Examples:
- fix: — bugfix
- feat: — feature
- refactor: — internal change without user-facing feature
- docs: — documentation only
- chore: — tooling, CI, deps, build housekeeping
- test: — tests only
-->

## Linked issue (required)

<!-- Fixes #123 / Closes #123 / Refs #123 -->
fixes #5006

## Steps to reproduce (required, use N/A if not applicable)

<!-- Steps to reproduce: how to trigger the bug in the broken state (the
"before").
 - Mainly for bugfixes;
    - For bugs: numbered steps before the fix. For non-bugs: write N/A.
 - use N/A for features, refactors, docs, chore, etc.
-->

> I. Undo duplication
> 
> (1) Write into the editor “line”.
> 
> (2) In the non html editor, select this line, then press the
unordered/ordered list button in the tool bar (or use keyword shortcut);
the html field of the editor becomes
> 
> ```
> <ol><li>line</li></ol>
> 
> ```
> 
> (3) Press the undo shortcut (command + Z on Mac)
> 
> Result: the list is still there, but its content is duplicated after
the list; the html field reads:
> 
> ```
> <ol><li>line</li></ol>line
> 
> ```
> 
> Remark: the same bug occurs when we begin with multiple lines instead
of just one.

## How to test (required)

<!--- How to test: how you verified the change (checks, unit tests,
manual steps, edge cases — the "after" or general validation). --->
Follow the reproduction steps. Undo should remove the text in the order
that it appeared.

### Checklist (minimum)

- [X] I ran `./ninja check` or an equivalent relevant check locally.
- [ ] I added or updated tests when the change is non-trivial or
behavior changed.

## Risk / compatibility / migration (optional)

<!-- Breaking changes, rollout notes, or N/A for small / low-risk PRs
-->

Undoes some of the behaviour from #3483. I couldn't reproduce the bug he
mentioned with this patch but I'm not entirely sure this doesn't re
introduce https://github.com/ankitects/anki/issues/3338 as a bug.

## Scope

- [X] This PR is focused on one change (no unrelated edits).
2026-06-22 18:30:13 +03:00
Luc Mcgrady
8fda6a3f4d docs: Re-add missing pages (#5049)
<!--
Title (for the Pull Request title field at the top):
Use a short prefix so the change type is obvious. You do not need to
repeat it in the body below.

Examples:
- fix: — bugfix
- feat: — feature
- refactor: — internal change without user-facing feature
- docs: — documentation only
- chore: — tooling, CI, deps, build housekeeping
- test: — tests only
-->

These pages are in the repo but are not used by the docs.

closes #5050
2026-06-22 13:22:10 +03:00
Luc Mcgrady
a6b2457a42 docs: use relative links (#5048)
<!--
Title (for the Pull Request title field at the top):
Use a short prefix so the change type is obvious. You do not need to
repeat it in the body below.

Examples:
- fix: — bugfix
- feat: — feature
- refactor: — internal change without user-facing feature
- docs: — documentation only
- chore: — tooling, CI, deps, build housekeeping
- test: — tests only
-->

## Linked issue (required)

closes #5011


All the "apps.ankiweb.net" Are broken in the form that they currently
exist which makes it difficult to confirm my changes would link to the
correct files so I've left them as they are in this pr.

---------

Co-authored-by: Abdo <abdo@abdnh.net>
2026-06-22 13:18:45 +03:00
RedPine404
29a2853f1d fix: Bump rust builder and base image for syncserver (#5036)
## Linked issue (required)

Fixes #5035

## Summary / motivation (required)

Rust builder is outdated an no longer builds the syncserver
successfully.

Bumping the version to match rust-toolchain.toml version 1.92.0 fixes
this issue.

I also bumped the base image to alpine:3.23 as alpine:3.21.0 is over a
year old.

## Steps to reproduce (required, use N/A if not applicable)

docker buildx build -f <Dockerfile> --no-cache --build-arg
ANKI_VERSION=<version> -t anki-sync-server .

## How to test (required)

docker buildx build -f <Dockerfile> --no-cache --build-arg
ANKI_VERSION=<version> -t anki-sync-server .

### Checklist (minimum)

- [x] I ran `docker buildx build -f Dockerfile --no-cache --build-arg
ANKI_VERSION=26.05 -t anki-sync-server .`
- [x] I ran `docker buildx build -f Dockerfile.distroless --no-cache
--build-arg ANKI_VERSION=26.05 -t anki-sync-server .`

### Details

Docker image compiled as expected following the updated versions.

## Scope

- [x] This PR is focused addressing the syncserver docker image.

Co-authored-by: Abdo <abdo@abdnh.net>
2026-06-19 18:10:39 +03:00
Konstantin Tutsch
daad13f01f fix: failing syncserver Docker build (#5021)
## Summary / motivation (required)

This PR fixes Docker Image builds for syncserver failing due to a Rust
version being used in both available Dockerfiles that is no longer
supported by the two dependencies `time@0.3.47` and `time-core@0.1.8`.

## Issue

Fixes #5022 

## Steps to reproduce (required, use N/A if not applicable)

1. `cd docs/syncserver`
2. `docker build -f Dockerfile --no-cache --build-arg ANKI_VERSION=26.05
-t anki-sync-server .`
3. Error (see issue)

## How to test (required)

1. `cd docs/syncserver`
2. `docker build -f Dockerfile --no-cache --build-arg ANKI_VERSION=26.05
-t anki-sync-server .`
3. run Docker image

## Scope

- [x] This PR is focused on one change (no unrelated edits).

Signed-off-by: Konstantin Tutsch <mail@konstantintutsch.com>
2026-06-19 18:06:47 +03:00
Luc Mcgrady
ff8e4f6e7a fix: move add_dynamic_styling_and_props_then_show to _on_load_finished (#4993)
<!--
Title (for the Pull Request title field at the top):
Use a short prefix so the change type is obvious. You do not need to
repeat it in the body below.

Examples:
- fix: — bugfix
- feat: — feature
- refactor: — internal change without user-facing feature
- docs: — documentation only
- chore: — tooling, CI, deps, build housekeeping
- test: — tests only
-->

## Linked issue (required)

<!-- Fixes #123 / Closes #123 / Refs #123 -->
Fixes #4992

## Summary / motivation (required)

<!-- What this PR does and why. For larger changes, add enough context
for reviewers. -->
This prevents the webview refreshing from affecting the styling of the
page.

## Steps to reproduce (required, use N/A if not applicable)

<!-- Steps to reproduce: how to trigger the bug in the broken state (the
"before").
 - Mainly for bugfixes;
    - For bugs: numbered steps before the fix. For non-bugs: write N/A.
 - use N/A for features, refactors, docs, chore, etc.
-->

1. Load an anki webview
2. Refresh it (Using the ankiview web inspector addon or otherwise)
3. The body will have none of the classes on it and none of the other
styling will be applied

## How to test (required)

<!--- How to test: how you verified the change (checks, unit tests,
manual steps, edge cases — the "after" or general validation). --->
Follow the reproduction steps and the classes should be the same as
before

### Checklist (minimum)

- [X] I ran `./ninja check` or an equivalent relevant check locally.
- [ ] I added or updated tests when the change is non-trivial or
behavior changed.

### Details

<!-- Commands, manual steps, edge cases, and what you observed -->

## Before / after behavior (optional)

<!-- For bugfixes: behavior before vs after. For other types: N/A or a
short note. -->

Before (After a refresh):
<img width="644" height="103" alt="image"
src="https://github.com/user-attachments/assets/888c1794-ed1a-447f-8b14-6cc631a1a1d3"
/>
After (After a refresh):
<img width="644" height="103" alt="image"
src="https://github.com/user-attachments/assets/49a7d6af-0292-4907-8faa-258d94190663"
/>

## Risk / compatibility / migration (optional)

<!-- Breaking changes, rollout notes, or N/A for small / low-risk PRs
-->

## UI evidence (required for visual changes; otherwise N/A)

<!-- Screenshot or short video -->

## Scope

- [X] This PR is focused on one change (no unrelated edits).
2026-06-19 17:49:26 +03:00
Arthur Milchior
b33f1d72e6 Fix: Correct "1 tags" to "1 tag" (#4967)
The string was either "Tags" if there is no tags, or "n Tags" if there
were a positive number of tags.

This ensure that for 1 tag, this does uses singular.

You can see the difference by opening the "add note" or the browser and
changing the number of tags.

Fixes: #4975.

---------

Co-authored-by: Abdo <abdo@abdnh.net>
2026-06-19 17:42:23 +03:00
Abdo
8f39ce82d5 chore: Sync with the 26.05 branch (#5041)
This syncs security fixes and translation/version updates from the 26.05
branch.

Related: #5039

---------

Co-authored-by: Andrew Sanchez <andrewsanchez@users.noreply.github.com>
Co-authored-by: Damien Elmes <gpg@ankiweb.net>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-19 16:36:51 +03:00
Abdo
3b705a1b9b fix: All-users MSI installation failing to detect existing installation (#5038)
## Linked issue

Closes #5037

## Summary

#4908 introduced a subtle issue for all-users MSI installations: it was
causing the installer to search for existing per-user installations
_only_, regardless of the user's choice. The fix is to set
`Schedule="afterInstallInitialize"` on the `MajorUpgrade` element so
that the search is done after the user's choice is resolved:
https://docs.firegiant.com/wix/schema/wxs/majorupgrade/

See template fix:
e028990d92

## Steps to reproduce (before)

1. Install
[26.05b2](https://github.com/ankitects/anki/releases/tag/26.05b2) and
choose the per-machine option in the Installation Scope page.
2. Install [26.05](https://github.com/ankitects/anki/releases/tag/26.05)
with the same scope.
3. Go to Windows' _Settings > Apps > Installed Apps_ and notice two Anki
entries.

## How to test (after)

Repeat the same process and confirm only one app entry.
2026-06-18 17:33:27 +03:00
Fernando Lins
d13f487bea test: add unit and integration tests for search service (#5024)
## Linked issue

Closes #4926

## Summary / motivation

`rslib/src/search/service/` had no test coverage. This PR adds tests
across two files (`mod.rs` and `search_node.rs`), covering:

- `TryFrom<SearchNode>` proto → domain conversions for all filter
variants
- `From<Rating>` and `From<CardState>` conversions
- `SearchService` RPC methods: `build_search_string`, `search_cards`,
`browser_row_for_id`, `replace_search_node`
- `SortMode` construction from proto, including the `Custom` fallback
- Error path: `build_search_string` with an empty group returns
`InvalidInput`
- Exact-match integration tests for deck, tag, and note-type filters in
`search_cards`


## How to test

```bash
just test-rust
```
2026-06-17 13:50:10 -03:00
Fernando Lins
2a715b211f test(notetype): add unit tests for notetype service layer (#5014)
## Linked issue

Closes #4925

## Summary / motivation

Adds a comprehensive unit test suite for
`rslib/src/notetype/service.rs`, which previously had zero tests. The
file implements the `NotetypesService` gRPC trait for `Collection` — 20
service methods and 6 `From` trait conversions used by both the Qt
frontend (via the legacy JSON adapter path) and the modern proto path.

Tests are organized into five commits by concern:

- **From trait conversions** (`NotetypeId` round-trip,
`ChangeNotetypeRequest ↔ ChangeNotetypeInput` mappings including the `-1
→ None` sentinel and `is_cloze` flag)
- **Legacy JSON adapters** (`add_notetype_legacy`,
`update_notetype_legacy`, `get_notetype_legacy`,
`get_stock_notetype_legacy` for all 6 stock kinds, and all 3 branches of
`add_or_update_notetype`)
- **CRUD service methods** (add, get, update, remove — happy paths,
error paths, and side effects such as card generation when a template is
added)
- **Auxiliary methods** (`get_notetype_names_and_counts`,
`get_aux_notetype_config_key`, `get_aux_template_config_key` including
the Cloze branch and the error path for unknown IDs)
- **Coverage threshold bump** (60 → 64)


## How to test

### Details

```bash
cargo test -p anki --lib "notetype::service::tests"
```

---------

Co-authored-by: Abdo <abdo@abdnh.net>
2026-06-17 17:32:00 +03:00
Luc Mcgrady
e9ac48cac2 Docs: Set up Prettier for formatting Mintlify website (#5020)
<!--
Title (for the Pull Request title field at the top):
Use a short prefix so the change type is obvious. You do not need to
repeat it in the body below.

Examples:
- fix: — bugfix
- feat: — feature
- refactor: — internal change without user-facing feature
- docs: — documentation only
- chore: — tooling, CI, deps, build housekeeping
- test: — tests only
-->

## Linked issue (required)

closes #5018
<!-- Fixes #123 / Closes #123 / Refs #123 -->

## Summary / motivation (required)

This prevents large diffs with prettier being used with the mintlify
editor

A caveat of this is that the docs generated by cog now have to be
prettier compatible. Also for some reason prettier has problems with the
{/* */} multi-line comment format so we have to use <!-- --> instead.

Sadly I don't have a good way to check that the Prettier config does not
differ between this PR and the editor.

---------

Co-authored-by: Abdo <abdo@abdnh.net>
2026-06-17 15:54:11 +03:00
Abdo
0d7b3fdd96 feat: Remove the uv launcher and old packaging code (#5019)
## Linked issue

Closes #4556
Closes #4557
Closes #4144
Closes #4151
Closes #4152
Closes #4153
Closes #4229
Closes #4356
Closes #4401
Closes #4403
Closes #4519
Closes #4523
Closes #4390
Closes #4414
Closes #4484



## Summary / motivation

After 4 months of exploring Briefcase for packaging, we're confident it
solves most problems with the uv launcher with less complexity and at a
lower maintenance cost, especially with the parallel work on the release
CI, which we already used to make 5 releases.

This also removes platform-specific packaging/signing code used to
produce macOS dmg files and Windows NSIS installers, which is now
largely handled by Briefcase and the release CI.
The custom install scripts for Linux are mostly preserved under
qt/installer/linux-template and used in the Briefcase build.

## How to test

- [ ] No build problems.
- [ ] The `tools/build-installer` scripts still work.
- [ ] No CI/release workflow issues.
- [ ] No user-visible changes in dev environment and Briefcase build.
2026-06-17 03:02:52 +03:00
Luc Mcgrady
2fcaa56023 Docs: use "Getting started" as manual index page (#5013)
- Updated docs-site/manual/getting-started.mdx
- Deleted docs-site/manual/index.mdx
- Updated docs-site/docs.json

Mintlify-Source: dashboard-editor

Please note that the Mintlify editor seems to make formatting changes to
files which it edits which makes this diff large than necessary.

closes #5000 

Uses the introduction / getting started pages as the index for each
category rather than a list of links.

Also re-introduces some pages that were missing from the FAQ to use as
the index as well.

I'm sorry about the large diff but mintlify makes formatting changes
when you use the editor.

---------

Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
2026-06-16 14:24:48 +03:00
Abdo
8ea145eb78 fix: Do not pass "--no-ytdl" to mpv on Intel Mac (#5015)
Fix audio broken on Intel Macs because our new mpv build doesn't
recognize the `--no-ytdl` option.
2026-06-15 21:10:03 +03:00
dependabot[bot]
b53d0a4169 chore(deps): bump pyo3 from 0.25.1 to 0.29.0 (#5002)
Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.25.1 to 0.29.0.

Closes #4999

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Abdo <abdo@abdnh.net>
2026-06-15 18:42:48 +03:00
Abdo
2d9651587a docs: Update docs for 26.05 (#5012)
## Linked issue

This syncs changes in https://github.com/ankitects/anki-manual/pull/497
to the new website.
Closes https://github.com/ankitects/anki-manual/issues/490
Closes #4696

## How to test

Run `mint dev` under the docs-site directory to view the website or go
to https://anki-release-docs.mintlify.app/

---------

Co-authored-by: Luc Mcgrady <lucmcgrady@gmail.com>
2026-06-15 18:15:41 +03:00
Abdo
098a6a4749 docs: Remove duplicate intro in README (#5003) 2026-06-15 17:18:27 +03:00
Abdo
76741b8b89 fix: Bump minimum required macOS version (#5010)
## Linked issue

Closes #5009

## Summary

Bump the minimum macOS version for the Briefcase build to 13.0 as
according to match Qt requirements.
2026-06-15 16:32:19 +03:00
Luc Mcgrady
8546af7cdf feat: hash script for github actions (#4991)
<!--
Title (for the Pull Request title field at the top):
Use a short prefix so the change type is obvious. You do not need to
repeat it in the body below.

Examples:
- fix: — bugfix
- feat: — feature
- refactor: — internal change without user-facing feature
- docs: — documentation only
- chore: — tooling, CI, deps, build housekeeping
- test: — tests only
-->

## Linked issue (required)

<!-- Fixes #123 / Closes #123 / Refs #123 -->
What I used to complete #4916

## Summary / motivation (required)

<!-- What this PR does and why. For larger changes, add enough context
for reviewers. -->
If we need to add more github actions in future this should make it easy

---------

Co-authored-by: Abdo <abdo@abdnh.net>
2026-06-12 23:13:08 +03:00
Abdo
80cf76e4f9 fix: Do not block MSI install if registry points to a deleted older installation (#4998)
## Linked issue

Closes #4997

## Summary

The MSI installer checks the Windows registry for older NSIS-based
installations and tries to run their uninstall.exe. If the registry
value is found but the uninstall file is missing for any reason, the
installer used to fail.

See template change:
8c4932ee1b

## Steps to reproduce (before)

1. Install
[25.09](https://github.com/ankitects/anki/releases/tag/25.09).
2. Go to the installation folder and delete uninstall.exe
3. Try to install
[26.05b2](https://github.com/ankitects/anki/releases/tag/26.05b2) - you
should see an error message as reported in the linked report.

## How to test (after)

1. Install 25.09.
2. Go to the installation folder and delete uninstall.exe.
3. Build the installer: `./tools/ninja installer:package`.
4. Run the installer and confirm it succeeds.
2026-06-12 19:43:26 +03:00
Andrew Sanchez
fb0215a2c1 Prototype unified Mintlify docs site (#4882)
## Summary

- add a generated `docs-site/` Mintlify proof of concept for a unified
Anki docs site
- migrate the desktop manual, AnkiMobile docs, FAQs, add-on docs,
translation docs, release notes, legacy docs, and repo-local Sphinx/MyST
developer docs into the POC tree
- add a migration helper that preserves mdBook ordering, handles common
MDX incompatibilities, and regenerates the landing-page-inspired
Mintlify styling
- apply minimal styling based on the current Anki landing page: Anki
logo, Hanken Grotesk, blue primary color, subtle surfaces, and compact
nav treatment

## Validation

- `uv run --with ty ty check tools/mintlify_poc_migrate.py`
- `source ~/.nvm/nvm.sh && nvm use 22.15.0 && mint validate`
- previewed locally with `mint dev --port 3000` and checked the home
page/developer docs in browser

## Notes

This is intentionally a draft POC. It does not remove the existing
Sphinx or mdBook docs flows yet; it demonstrates what bringing the
sources into this repo and building from a single Mintlify root could
look like.

---------

Co-authored-by: Andrew Sanchez <andrewsanchez@users.noreply.github.com>
Co-authored-by: Luc Mcgrady <lucmcgrady@gmail.com>
Co-authored-by: Abdo <abdo@abdnh.net>
2026-06-12 16:27:33 +03:00
Fernando Lins
02e16b5473 fix(csv): use csv reader in column position tests to handle quoted fields (#4994)
## Linked issue

Fixes CI failure introduced by #4927

## Summary / motivation

The column-position tests added in the previous PR were failing in CI on
Linux. Anki GUIDs use a base91 charset that includes `"` (double quote).
When a GUID contains `"`, the CSV writer correctly wraps the field in
quotes, but the tests were splitting the raw line by `\t`, which
returned the surrounding quotes as part of the value:
```
left: ""AtI#}YcFn"" ← field value including CSV quotes right: "AtI#}YcFn" ← the actual GUID
```

The fix replaces manual `split('\t')` with `csv::ReaderBuilder` in both
affected tests. This is also the semantically correct approach: the same
parser the importer uses, which automatically unquotes fields.

The bug only manifested on Linux because the randomly generated GUID on
macOS happened not to contain `"`.

## How to test 

```bash
cargo test -p anki --lib "import_export::text::csv::export::tests"
```
All 18 tests pass.
2026-06-11 11:00:15 -03:00
Abdo
a4308206ad chore: Run complexipy-diff as part of ninja check (#4987)
## Linked issue

Closes #4986
Closes #4985

## Summary

- Move the complexipy-diff check to Ninja so it can be run locally as
part of `./ninja check`.
- Fix
[SARIF](https://docs.github.com/en/code-security/reference/code-scanning/sarif-files/sarif-support)
results not being uploaded if the Complexipy check fails.

## Steps to reproduce (before)

complexipy-diff was only run on CI and pre-push automatically. It was
not covered by ninja check, which is not consistent with most tests and
tools.

## How to test (after)

- Run `./ninja check:complexipy-diff` and confirm it passes.
- Introduce some complex Python change (e.g. add some nested if
statements) so that the check fails now.
- Update your pre-commit config: `./out/extracted/uv/uv run pre-commit
install`.
2026-06-10 21:04:15 +03:00
Luc Mcgrady
fbe2d93654 docs: include aqt in tree (#4984)
<!--
Title (for the Pull Request title field at the top):
Use a short prefix so the change type is obvious. You do not need to
repeat it in the body below.

Examples:
- fix: — bugfix
- feat: — feature
- refactor: — internal change without user-facing feature
- docs: — documentation only
- chore: — tooling, CI, deps, build housekeeping
- test: — tests only
-->

## Linked issue (required)

<!-- Fixes #123 / Closes #123 / Refs #123 -->
closes #4983

## Summary / motivation (required)

<!-- What this PR does and why. For larger changes, add enough context
for reviewers. -->
This pr adds links to the aqt section of the docs.

### Details

<!-- Commands, manual steps, edge cases, and what you observed -->

## UI evidence (required for visual changes; otherwise N/A)

<img width="306" height="111" alt="image"
src="https://github.com/user-attachments/assets/39111e4f-8aa1-4865-b193-0da949967618"
/>

## Scope

- [X] This PR is focused on one change (no unrelated edits).

---------

Co-authored-by: Abdo <abdo@abdnh.net>
2026-06-10 20:40:29 +03:00
Fernando Lins
a5086f1def test: add unit tests for CSV export and import-export service layer (#4976)
## Linked issue

Closes #4927

## Summary / motivation

`rslib/src/import_export/service.rs` and
`rslib/src/import_export/text/csv/export.rs` had no unit test coverage.
This PR adds tests for the meaningful logic in both modules: type
conversions, error propagation, config defaults, and CSV
structure/content.

**`service.rs`**
- All 4 branches of `From<ExportLimit> for SearchNode` (None, DeckId,
NoteIds, CardIds)
- `get_import_anki_package_presets` default config values
- `export_card_csv` / `export_note_csv` `UInt32` return type
- Error propagation for all I/O functions (`import_anki_package`,
`import_csv`, `import_json_file`, `import_json_string`,
`export_card_csv`, `export_note_csv`, `export_anki_package`)
- Success paths using a real `.apkg` fixture, temp CSV, and temp JSON
files
- `From<OpOutput<NoteLog>> for ImportResponse` field mapping

**`text/csv/export.rs`**
- Card CSV: header format, empty collection writes header, count
(single/multiple/filtered by deck), front/back in correct tab-separated
columns, HTML preserved and stripped
- Note CSV: count (single/multiple/filtered by deck), exact column index
values, column headers absent when metadata disabled, fields and GUID in
correct columns, GUID omitted when `with_guid: false`, HTML preserved
and stripped

**`text/csv/metadata.rs`**
- Extends `should_detect_valid_delimiters` to cover the last-resort
`Delimiter::Space` fallback when the file has no recognizable separator
in its content

## How to test

```bash
cargo test -p anki --lib "import_export::service::tests"
cargo test -p anki --lib "import_export::text::csv::export::tests"
cargo test -p anki --lib "import_export::text::csv::metadata::test::should_detect_valid_delimiters"
```

All 18 tests in export.rs, all tests in service.rs, and the delimiter
test pass.
2026-06-10 14:23:05 -03:00
Abdo
9dca79de1f Rerun check-linked-issue.yml on labeled event (#4979)
This triggers the check-linked-issue.yml workflow on the `labeled`
event, so that if the `hotfix` label is added later after the PR is
opened, the workflow is rerun.
2026-06-10 09:51:20 -03:00
Fernando Lins
918004570b chore(ci): use pull_request_target to fix write perms on fork PRs (#4977)
## Summary / motivation

The `check-linked-issue` workflow was triggering with the `pull_request`
event. This caused the step "Apply missing-issue label and comment" to
fail with:

> HttpError: Resource not accessible by integration

Switching to `pull_request_target` makes the workflow run in the context
of the base repository instead of the fork, so the declared write
permissions are honoured.

The change is safe because this workflow never checks out PR code. It
only reads PR metadata (body, labels) through the API. There is no risk
of running untrusted code with elevated permissions.

## Steps to reproduce

1. Open a PR from an external fork that has no linked issue.
2. Observe the "Check Linked Issue" CI job failing with
   `HttpError: Resource not accessible by integration`.

## Before / after behavior

**Before:** workflow crashes on every fork PR that lacks a linked issue.
**After:** workflow applies the label and posts the comment as intended.
2026-06-10 11:32:34 +03:00
user1823
83d711ff0b Feat: Expose card's decay and DR to custom scheduler (#4880)
I wanted to use the card's decay in my custom scheduling script. But,
Anki doesn't expose it to JS. This small change exposes the values to
JS.
2026-06-08 20:26:42 +03:00
Lee Doughty
d76bd4033b test: cover attribute and tag stripping in HTML filter (#4965)
## Linked issue

Closes #4929

## Summary / motivation

`ts/html-filter/element.ts` is responsible for sanitizing HTML on paste
in the note editor, so it's security-sensitive code. About 8% of it
wasn't covered by tests, including the branches that strip attributes
and tags. This PR adds tests to get it to full coverage (statements,
branches, functions, and lines) so we don't accidentally break the
filtering later. There are no changes to the actual code, just tests.

## Steps to reproduce

N/A - tests only.

## How to test

### Checklist (minimum)

- [x] I ran `./ninja check` or an equivalent relevant check locally.
- [x] I added or updated tests when the change is non-trivial or
behaviour changed.

### Details

Ran `just check` (the full lint and test build) and everything passed.

For coverage specifically, I scoped vitest to the target file:

`npx vitest run html-filter/index.test.ts --coverage
--coverage.include='html-filter/element.ts'`

That reports element.ts at 100% for statements, branches, functions, and
lines.

New tests cover:
- event handler attributes (`onclick`/`onerror`) stripped from allowed
elements
- `<script>` removal, including empty and nested cases
- unknown/disallowed tags dropped (empty) or unwrapped (with content)
- `<span>` styling honouring night mode (the previously uncovered
branch)

## Before / after behavior

N/A - no behaviour change, tests document existing behaviour.

## UI evidence

N/A

## Scope

- [x] This PR is focused on one change (no unrelated edits).

**Note for reviewers:** the originating issue listed "verify `<p>` →
`<div>` conversion" as a criterion, but `element.ts` treats `<p>` as an
allowed tag (`P: allowNone`) and preserves it, so there is no `p`→`div`
conversion in this component. The tests document the actual behaviour
(`<p>` kept, attributes stripped). Happy to adjust if a conversion was
intended elsewhere.

---------

Co-authored-by: Fernando Lins <1887601+fernandolins@users.noreply.github.com>
2026-06-08 14:08:49 -03:00
Abdo
08a0780417 fix: Preserve .tar.zst suffix of Linux release zip (#4961)
## Linked issue

Closes #4960


## Steps to reproduce (before)

The latest beta zips have only ".zst" as the suffix:
https://github.com/ankitects/anki/releases/tag/26.05b2

## How to test (after)

Check the artifacts of this GHA run and confirm the suffix is preserved:
https://github.com/ankitects/anki/actions/runs/27027272624
2026-06-08 18:09:44 +03:00
Fernando Lins
02210ec450 test(scheduler): add unit tests for learning and relearning state transitions (#4963)
## Linked issue

Closes #4928

## Summary / motivation

`learning.rs` and `relearning.rs` had 0% test coverage. They implement
the core scheduling logic for new and lapsed cards — a regression here
affects every user's review queue silently. This PR adds unit tests to
establish a safety net before future migrations or FSRS changes touch
this code.

## How to test

```bash
cargo test -p anki --lib "states::learning::tests"
cargo test -p anki --lib "states::relearning::tests"
```

## Details

`learning.rs` — tests covering all four buttons under SM-2: again (reset
to first step, no-steps graduation), hard (same step, no-steps
graduation), good (advance or graduate), easy (always graduates,
interval ordering invariant), plus FSRS routing stubs.

`relearning.rs` — tests covering SM-2 transitions (lapse penalty, step
keep/reset/graduate), FSRS routing (long interval → Review, short-term →
Relearning for all buttons), and multi-step behavior (again resets, hard
keeps, good advances through intermediate steps).
2026-06-08 11:59:54 -03:00
Abdo
76c0407ccc fix: Repaint UI after answer reveal (#4970)
## Linked issue

Closes #4969

## Summary

Add a [QWidget.update()](https://doc.qt.io/qt-6/qwidget.html#update)
call for the main webview after the answer is revealed and images are
loaded. This should reduce UI glitches, especially on cards with images.

## How to test

It's hard to test and reproduce this, because its frequency varies
between operating systems and graphics drivers.
I've seen improvements on my collection on Windows with the default
video driver (Direct3D) while doing my daily reviews today with this
change and I'll continue testing over the week.
2026-06-08 17:51:15 +03:00
Abdo
8034ebc160 chore: Tweak gh release name (#4964)
Remove "Anki" from the titles of releases.
2026-06-08 15:58:20 +03:00
Fernando Lins
110cb8f3b1 fix(sass): replace global map-get/map-merge with sass:map namespace in _functions.scss (#4955)
## Summary

Closes #4954.

`_functions.scss` already had `@use "sass:map"` at the top but was still
calling the deprecated global functions `map-get` and `map-merge`.
Replaced all occurrences with their namespaced equivalents `map.get` and
`map.merge`.

This eliminates the `[global-builtin]` deprecation warnings visible in
every Check (Linux) CI run, which will become hard errors in Dart Sass
3.0.

## Test plan

- [x] `just lint` passes
- [x] `just test-ts` passes with no deprecation warnings

## Before / after behavior (optional)

### at main branch
<img width="1325" height="906" alt="Image"
src="https://github.com/user-attachments/assets/6a35ac2d-418a-4ded-baf6-f959b06b8d48"
/>

### at this branch
<img width="1156" height="921" alt="image"
src="https://github.com/user-attachments/assets/276a15ce-b319-4ee5-9ae2-122cd4d4d45e"
/>
2026-06-05 09:25:14 -03:00