mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 08:46:37 -04:00
Switch CardInfoDialog to ts page (#1414)
* Only collect card stats on the backend ... ... instead of rendering an HTML string using askama. * Add ts page Card Info * Update test for new `col.card_stats()` * Remove obsolete CardStats code * Use new ts page in `CardInfoDialog` * Align start and end instead of left and right Curiously, `text-align: start` does not work for `th` tags if assigned via classes. * Adopt ts refactorings after rebase #1405 and #1409 * Clean up `ts/card-info/BUILD.bazel` * Port card info logic from Rust to TS * Move repeated field to the top https://github.com/ankitects/anki/pull/1414#discussion_r725402730 * Convert pseudo classes to interfaces * CardInfoPage -> CardInfo * Make revlog in card info optional * Add legacy support for old card stats * Check for undefined instead of falsy * Make Revlog separate component * drop askama dependency (dae) * Fix nightmode for legacy card stats
This commit is contained in:
parent
7128de895f
commit
3672b0fe73
46 changed files with 648 additions and 1705 deletions
129
Cargo.lock
generated
129
Cargo.lock
generated
|
@ -55,7 +55,6 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"ammonia",
|
||||
"anki_i18n",
|
||||
"askama",
|
||||
"async-trait",
|
||||
"blake3",
|
||||
"bytes",
|
||||
|
@ -73,7 +72,7 @@ dependencies = [
|
|||
"itertools",
|
||||
"lazy_static",
|
||||
"linkcheck",
|
||||
"nom 7.0.0",
|
||||
"nom",
|
||||
"num-integer",
|
||||
"num_enum",
|
||||
"once_cell",
|
||||
|
@ -158,64 +157,12 @@ dependencies = [
|
|||
"nodrop",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d298738b6e47e1034e560e5afe63aa488fea34e25ec11b855a76f0d7b8e73134"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
"askama_escape",
|
||||
"askama_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2925c4c290382f9d2fa3d1c1b6a63fa1427099721ecca4749b154cc9c25522"
|
||||
dependencies = [
|
||||
"askama_shared",
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_escape"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90c108c1a94380c89d2215d0ac54ce09796823cca0fd91b299cfff3b33e346fb"
|
||||
|
||||
[[package]]
|
||||
name = "askama_shared"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2582b77e0f3c506ec4838a25fa8a5f97b9bed72bb6d3d272ea1c031d8bd373bc"
|
||||
dependencies = [
|
||||
"askama_escape",
|
||||
"humansize",
|
||||
"nom 6.1.2",
|
||||
"num-traits",
|
||||
"percent-encoding",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.51"
|
||||
|
@ -256,18 +203,6 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "0.19.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321"
|
||||
dependencies = [
|
||||
"funty",
|
||||
"radium",
|
||||
"tap",
|
||||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.0.0"
|
||||
|
@ -650,12 +585,6 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
|
||||
|
||||
[[package]]
|
||||
name = "futf"
|
||||
version = "0.1.4"
|
||||
|
@ -925,12 +854,6 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
|
||||
|
||||
[[package]]
|
||||
name = "humansize"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
|
@ -1127,19 +1050,6 @@ version = "1.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "lexical-core"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
|
||||
dependencies = [
|
||||
"arrayvec 0.5.2",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"ryu",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.103"
|
||||
|
@ -1346,19 +1256,6 @@ version = "0.1.14"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "6.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"funty",
|
||||
"lexical-core",
|
||||
"memchr",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.0.0"
|
||||
|
@ -1902,12 +1799,6 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "radium"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
|
@ -2473,12 +2364,6 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.1"
|
||||
|
@ -2542,12 +2427,6 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
|
||||
|
||||
[[package]]
|
||||
name = "tap"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.2.0"
|
||||
|
@ -3162,12 +3041,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
|
||||
|
||||
[[package]]
|
||||
name = "xml5ever"
|
||||
version = "0.16.1"
|
||||
|
|
140
cargo/crates.bzl
140
cargo/crates.bzl
|
@ -101,16 +101,6 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.arrayvec-0.4.12.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__arrayvec__0_5_2",
|
||||
url = "https://crates.io/api/v1/crates/arrayvec/0.5.2/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b",
|
||||
strip_prefix = "arrayvec-0.5.2",
|
||||
build_file = Label("//cargo/remote:BUILD.arrayvec-0.5.2.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__arrayvec__0_7_1",
|
||||
|
@ -121,46 +111,6 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.arrayvec-0.7.1.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__askama__0_10_5",
|
||||
url = "https://crates.io/api/v1/crates/askama/0.10.5/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "d298738b6e47e1034e560e5afe63aa488fea34e25ec11b855a76f0d7b8e73134",
|
||||
strip_prefix = "askama-0.10.5",
|
||||
build_file = Label("//cargo/remote:BUILD.askama-0.10.5.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__askama_derive__0_10_5",
|
||||
url = "https://crates.io/api/v1/crates/askama_derive/0.10.5/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "ca2925c4c290382f9d2fa3d1c1b6a63fa1427099721ecca4749b154cc9c25522",
|
||||
strip_prefix = "askama_derive-0.10.5",
|
||||
build_file = Label("//cargo/remote:BUILD.askama_derive-0.10.5.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__askama_escape__0_10_1",
|
||||
url = "https://crates.io/api/v1/crates/askama_escape/0.10.1/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "90c108c1a94380c89d2215d0ac54ce09796823cca0fd91b299cfff3b33e346fb",
|
||||
strip_prefix = "askama_escape-0.10.1",
|
||||
build_file = Label("//cargo/remote:BUILD.askama_escape-0.10.1.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__askama_shared__0_11_1",
|
||||
url = "https://crates.io/api/v1/crates/askama_shared/0.11.1/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "2582b77e0f3c506ec4838a25fa8a5f97b9bed72bb6d3d272ea1c031d8bd373bc",
|
||||
strip_prefix = "askama_shared-0.11.1",
|
||||
build_file = Label("//cargo/remote:BUILD.askama_shared-0.11.1.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__async_trait__0_1_51",
|
||||
|
@ -211,16 +161,6 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.bitflags-1.3.2.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__bitvec__0_19_5",
|
||||
url = "https://crates.io/api/v1/crates/bitvec/0.19.5/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321",
|
||||
strip_prefix = "bitvec-0.19.5",
|
||||
build_file = Label("//cargo/remote:BUILD.bitvec-0.19.5.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__blake3__1_0_0",
|
||||
|
@ -641,16 +581,6 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.form_urlencoded-1.0.1.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__funty__1_1_0",
|
||||
url = "https://crates.io/api/v1/crates/funty/1.1.0/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7",
|
||||
strip_prefix = "funty-1.1.0",
|
||||
build_file = Label("//cargo/remote:BUILD.funty-1.1.0.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__futf__0_1_4",
|
||||
|
@ -921,16 +851,6 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.httpdate-1.0.1.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__humansize__1_1_1",
|
||||
url = "https://crates.io/api/v1/crates/humansize/1.1.1/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026",
|
||||
strip_prefix = "humansize-1.1.1",
|
||||
build_file = Label("//cargo/remote:BUILD.humansize-1.1.1.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__humantime__2_1_0",
|
||||
|
@ -1121,16 +1041,6 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.lazy_static-1.4.0.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__lexical_core__0_7_6",
|
||||
url = "https://crates.io/api/v1/crates/lexical-core/0.7.6/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe",
|
||||
strip_prefix = "lexical-core-0.7.6",
|
||||
build_file = Label("//cargo/remote:BUILD.lexical-core-0.7.6.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__libc__0_2_103",
|
||||
|
@ -1351,16 +1261,6 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.nodrop-0.1.14.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__nom__6_1_2",
|
||||
url = "https://crates.io/api/v1/crates/nom/6.1.2/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2",
|
||||
strip_prefix = "nom-6.1.2",
|
||||
build_file = Label("//cargo/remote:BUILD.nom-6.1.2.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__nom__7_0_0",
|
||||
|
@ -1901,16 +1801,6 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.quote-1.0.9.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__radium__0_5_3",
|
||||
url = "https://crates.io/api/v1/crates/radium/0.5.3/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8",
|
||||
strip_prefix = "radium-0.5.3",
|
||||
build_file = Label("//cargo/remote:BUILD.radium-0.5.3.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__rand__0_7_3",
|
||||
|
@ -2441,16 +2331,6 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.stable_deref_trait-1.2.0.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__static_assertions__1_1_0",
|
||||
url = "https://crates.io/api/v1/crates/static_assertions/1.1.0/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f",
|
||||
strip_prefix = "static_assertions-1.1.0",
|
||||
build_file = Label("//cargo/remote:BUILD.static_assertions-1.1.0.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__string_cache__0_8_1",
|
||||
|
@ -2511,16 +2391,6 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.take_mut-0.2.2.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__tap__1_0_1",
|
||||
url = "https://crates.io/api/v1/crates/tap/1.0.1/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369",
|
||||
strip_prefix = "tap-1.0.1",
|
||||
build_file = Label("//cargo/remote:BUILD.tap-1.0.1.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__tempfile__3_2_0",
|
||||
|
@ -3201,16 +3071,6 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.winreg-0.7.0.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__wyz__0_2_0",
|
||||
url = "https://crates.io/api/v1/crates/wyz/0.2.0/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214",
|
||||
strip_prefix = "wyz-0.2.0",
|
||||
build_file = Label("//cargo/remote:BUILD.wyz-0.2.0.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__xml5ever__0_16_1",
|
||||
|
|
|
@ -107,15 +107,6 @@
|
|||
"license_file": null,
|
||||
"description": "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString."
|
||||
},
|
||||
{
|
||||
"name": "arrayvec",
|
||||
"version": "0.5.2",
|
||||
"authors": "bluss",
|
||||
"repository": "https://github.com/bluss/arrayvec",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"license_file": null,
|
||||
"description": "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString."
|
||||
},
|
||||
{
|
||||
"name": "arrayvec",
|
||||
"version": "0.7.1",
|
||||
|
@ -125,42 +116,6 @@
|
|||
"license_file": null,
|
||||
"description": "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString."
|
||||
},
|
||||
{
|
||||
"name": "askama",
|
||||
"version": "0.10.5",
|
||||
"authors": "Dirkjan Ochtman <dirkjan@ochtman.nl>",
|
||||
"repository": "https://github.com/djc/askama",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"license_file": null,
|
||||
"description": "Type-safe, compiled Jinja-like templates for Rust"
|
||||
},
|
||||
{
|
||||
"name": "askama_derive",
|
||||
"version": "0.10.5",
|
||||
"authors": "Dirkjan Ochtman <dirkjan@ochtman.nl>",
|
||||
"repository": "https://github.com/djc/askama",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"license_file": null,
|
||||
"description": "Procedural macro package for Askama"
|
||||
},
|
||||
{
|
||||
"name": "askama_escape",
|
||||
"version": "0.10.1",
|
||||
"authors": "Dirkjan Ochtman <dirkjan@ochtman.nl>",
|
||||
"repository": "https://github.com/djc/askama",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"license_file": null,
|
||||
"description": "Optimized HTML escaping code, extracted from Askama"
|
||||
},
|
||||
{
|
||||
"name": "askama_shared",
|
||||
"version": "0.11.1",
|
||||
"authors": "Dirkjan Ochtman <dirkjan@ochtman.nl>",
|
||||
"repository": "https://github.com/djc/askama",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"license_file": null,
|
||||
"description": "Shared code for Askama"
|
||||
},
|
||||
{
|
||||
"name": "async-trait",
|
||||
"version": "0.1.51",
|
||||
|
@ -206,15 +161,6 @@
|
|||
"license_file": null,
|
||||
"description": "A macro to generate structures which behave like bitflags."
|
||||
},
|
||||
{
|
||||
"name": "bitvec",
|
||||
"version": "0.19.5",
|
||||
"authors": "myrrlyn <self@myrrlyn.dev>",
|
||||
"repository": "https://github.com/myrrlyn/bitvec",
|
||||
"license": "MIT",
|
||||
"license_file": null,
|
||||
"description": "A crate for manipulating memory, bit by bit"
|
||||
},
|
||||
{
|
||||
"name": "blake3",
|
||||
"version": "1.0.0",
|
||||
|
@ -593,15 +539,6 @@
|
|||
"license_file": null,
|
||||
"description": "Parser and serializer for the application/x-www-form-urlencoded syntax, as used by HTML forms."
|
||||
},
|
||||
{
|
||||
"name": "funty",
|
||||
"version": "1.1.0",
|
||||
"authors": "myrrlyn <self@myrrlyn.dev>",
|
||||
"repository": "https://github.com/myrrlyn/funty",
|
||||
"license": "MIT",
|
||||
"license_file": null,
|
||||
"description": "Trait generalization over the primitive types"
|
||||
},
|
||||
{
|
||||
"name": "futf",
|
||||
"version": "0.1.4",
|
||||
|
@ -845,15 +782,6 @@
|
|||
"license_file": null,
|
||||
"description": "HTTP date parsing and formatting"
|
||||
},
|
||||
{
|
||||
"name": "humansize",
|
||||
"version": "1.1.1",
|
||||
"authors": "Leopold Arkham <leopold.arkham@gmail.com>",
|
||||
"repository": "https://github.com/LeopoldArkham/humansize",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"license_file": null,
|
||||
"description": "A configurable crate to easily represent file sizes in a human-readable format."
|
||||
},
|
||||
{
|
||||
"name": "humantime",
|
||||
"version": "2.1.0",
|
||||
|
@ -1025,15 +953,6 @@
|
|||
"license_file": null,
|
||||
"description": "A macro for declaring lazily evaluated statics in Rust."
|
||||
},
|
||||
{
|
||||
"name": "lexical-core",
|
||||
"version": "0.7.6",
|
||||
"authors": "Alex Huszagh <ahuszagh@gmail.com>",
|
||||
"repository": "https://github.com/Alexhuszagh/rust-lexical/tree/master/lexical-core",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"license_file": null,
|
||||
"description": "Lexical, to- and from-string conversion routines."
|
||||
},
|
||||
{
|
||||
"name": "libc",
|
||||
"version": "0.2.103",
|
||||
|
@ -1232,15 +1151,6 @@
|
|||
"license_file": null,
|
||||
"description": "A wrapper type to inhibit drop (destructor). ***Deprecated: Use ManuallyDrop or MaybeUninit instead!***"
|
||||
},
|
||||
{
|
||||
"name": "nom",
|
||||
"version": "6.1.2",
|
||||
"authors": "contact@geoffroycouprie.com",
|
||||
"repository": "https://github.com/Geal/nom",
|
||||
"license": "MIT",
|
||||
"license_file": null,
|
||||
"description": "A byte-oriented, zero-copy, parser combinators library"
|
||||
},
|
||||
{
|
||||
"name": "nom",
|
||||
"version": "7.0.0",
|
||||
|
@ -1727,15 +1637,6 @@
|
|||
"license_file": null,
|
||||
"description": "Quasi-quoting macro quote!(...)"
|
||||
},
|
||||
{
|
||||
"name": "radium",
|
||||
"version": "0.5.3",
|
||||
"authors": "Nika Layzell <nika@thelayzells.com>|myrrlyn <self@myrrlyn.dev>",
|
||||
"repository": "https://github.com/mystor/radium",
|
||||
"license": "MIT",
|
||||
"license_file": null,
|
||||
"description": "Helper traits for working with maybe-atomic values"
|
||||
},
|
||||
{
|
||||
"name": "rand",
|
||||
"version": "0.7.3",
|
||||
|
@ -2222,15 +2123,6 @@
|
|||
"license_file": null,
|
||||
"description": "An unsafe marker trait for types like Box and Rc that dereference to a stable address even when moved, and hence can be used with libraries such as owning_ref and rental."
|
||||
},
|
||||
{
|
||||
"name": "static_assertions",
|
||||
"version": "1.1.0",
|
||||
"authors": "Nikolai Vazquez",
|
||||
"repository": "https://github.com/nvzqz/static-assertions-rs",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"license_file": null,
|
||||
"description": "Compile-time assertions to ensure that invariants are met."
|
||||
},
|
||||
{
|
||||
"name": "string_cache",
|
||||
"version": "0.8.1",
|
||||
|
@ -2285,15 +2177,6 @@
|
|||
"license_file": null,
|
||||
"description": "Take a T from a &mut T temporarily"
|
||||
},
|
||||
{
|
||||
"name": "tap",
|
||||
"version": "1.0.1",
|
||||
"authors": "Elliott Linder <elliott.darfink@gmail.com>|myrrlyn <self@myrrlyn.dev>",
|
||||
"repository": "https://github.com/myrrlyn/tap",
|
||||
"license": "MIT",
|
||||
"license_file": null,
|
||||
"description": "Generic extensions for tapping values in Rust"
|
||||
},
|
||||
{
|
||||
"name": "tempfile",
|
||||
"version": "3.2.0",
|
||||
|
@ -2906,15 +2789,6 @@
|
|||
"license_file": null,
|
||||
"description": "Rust bindings to MS Windows Registry API"
|
||||
},
|
||||
{
|
||||
"name": "wyz",
|
||||
"version": "0.2.0",
|
||||
"authors": "myrrlyn <self@myrrlyn.dev>",
|
||||
"repository": "https://github.com/myrrlyn/wyz",
|
||||
"license": "MIT",
|
||||
"license_file": null,
|
||||
"description": "myrrlyn’s utility collection"
|
||||
},
|
||||
{
|
||||
"name": "xml5ever",
|
||||
"version": "0.16.1",
|
||||
|
|
62
cargo/remote/BUILD.arrayvec-0.5.2.bazel
vendored
62
cargo/remote/BUILD.arrayvec-0.5.2.bazel
vendored
|
@ -1,62 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT OR Apache-2.0"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
# Unsupported target "arraystring" with type "bench" omitted
|
||||
|
||||
# Unsupported target "extend" with type "bench" omitted
|
||||
|
||||
rust_library(
|
||||
name = "arrayvec",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"array-sizes-33-128",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.5.2",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
],
|
||||
)
|
||||
|
||||
# Unsupported target "serde" with type "test" omitted
|
||||
|
||||
# Unsupported target "tests" with type "test" omitted
|
63
cargo/remote/BUILD.askama-0.10.5.bazel
vendored
63
cargo/remote/BUILD.askama-0.10.5.bazel
vendored
|
@ -1,63 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT OR Apache-2.0"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
rust_library(
|
||||
name = "askama",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"config",
|
||||
"default",
|
||||
"humansize",
|
||||
"num-traits",
|
||||
"urlencode",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
proc_macro_deps = [
|
||||
"@raze__askama_derive__0_10_5//:askama_derive",
|
||||
],
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.10.5",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
"@raze__askama_escape__0_10_1//:askama_escape",
|
||||
"@raze__askama_shared__0_11_1//:askama_shared",
|
||||
],
|
||||
)
|
56
cargo/remote/BUILD.askama_derive-0.10.5.bazel
vendored
56
cargo/remote/BUILD.askama_derive-0.10.5.bazel
vendored
|
@ -1,56 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT OR Apache-2.0"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
rust_library(
|
||||
name = "askama_derive",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "proc-macro",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.10.5",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
"@raze__askama_shared__0_11_1//:askama_shared",
|
||||
"@raze__proc_macro2__1_0_29//:proc_macro2",
|
||||
"@raze__syn__1_0_77//:syn",
|
||||
],
|
||||
)
|
55
cargo/remote/BUILD.askama_escape-0.10.1.bazel
vendored
55
cargo/remote/BUILD.askama_escape-0.10.1.bazel
vendored
|
@ -1,55 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT OR Apache-2.0"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
# Unsupported target "all" with type "bench" omitted
|
||||
|
||||
rust_library(
|
||||
name = "askama_escape",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.10.1",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
],
|
||||
)
|
69
cargo/remote/BUILD.askama_shared-0.11.1.bazel
vendored
69
cargo/remote/BUILD.askama_shared-0.11.1.bazel
vendored
|
@ -1,69 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT OR Apache-2.0"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
rust_library(
|
||||
name = "askama_shared",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"config",
|
||||
"humansize",
|
||||
"num-traits",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"toml",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.11.1",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
"@raze__askama_escape__0_10_1//:askama_escape",
|
||||
"@raze__humansize__1_1_1//:humansize",
|
||||
"@raze__nom__6_1_2//:nom",
|
||||
"@raze__num_traits__0_2_14//:num_traits",
|
||||
"@raze__percent_encoding__2_1_0//:percent_encoding",
|
||||
"@raze__proc_macro2__1_0_29//:proc_macro2",
|
||||
"@raze__quote__1_0_9//:quote",
|
||||
"@raze__serde__1_0_130//:serde",
|
||||
"@raze__syn__1_0_77//:syn",
|
||||
"@raze__toml__0_5_8//:toml",
|
||||
],
|
||||
)
|
65
cargo/remote/BUILD.bitvec-0.19.5.bazel
vendored
65
cargo/remote/BUILD.bitvec-0.19.5.bazel
vendored
|
@ -1,65 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
# Unsupported target "macros" with type "bench" omitted
|
||||
|
||||
# Unsupported target "memcpy" with type "bench" omitted
|
||||
|
||||
# Unsupported target "slice" with type "bench" omitted
|
||||
|
||||
rust_library(
|
||||
name = "bitvec",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"alloc",
|
||||
"std",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.19.5",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
"@raze__funty__1_1_0//:funty",
|
||||
"@raze__radium__0_5_3//:radium",
|
||||
"@raze__tap__1_0_1//:tap",
|
||||
"@raze__wyz__0_2_0//:wyz",
|
||||
],
|
||||
)
|
53
cargo/remote/BUILD.funty-1.1.0.bazel
vendored
53
cargo/remote/BUILD.funty-1.1.0.bazel
vendored
|
@ -1,53 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
rust_library(
|
||||
name = "funty",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "1.1.0",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
],
|
||||
)
|
57
cargo/remote/BUILD.humansize-1.1.1.bazel
vendored
57
cargo/remote/BUILD.humansize-1.1.1.bazel
vendored
|
@ -1,57 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT OR Apache-2.0"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
# Unsupported target "custom_options" with type "example" omitted
|
||||
|
||||
# Unsupported target "sizes" with type "example" omitted
|
||||
|
||||
rust_library(
|
||||
name = "humansize",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2015",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "1.1.1",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
],
|
||||
)
|
102
cargo/remote/BUILD.lexical-core-0.7.6.bazel
vendored
102
cargo/remote/BUILD.lexical-core-0.7.6.bazel
vendored
|
@ -1,102 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT OR Apache-2.0"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
# buildifier: disable=out-of-order-load
|
||||
# buildifier: disable=load-on-top
|
||||
load(
|
||||
"@rules_rust//cargo:cargo_build_script.bzl",
|
||||
"cargo_build_script",
|
||||
)
|
||||
|
||||
cargo_build_script(
|
||||
name = "lexical_core_build_script",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
build_script_env = {
|
||||
},
|
||||
crate_features = [
|
||||
"arrayvec",
|
||||
"correct",
|
||||
"default",
|
||||
"ryu",
|
||||
"static_assertions",
|
||||
"std",
|
||||
"table",
|
||||
],
|
||||
crate_root = "build.rs",
|
||||
data = glob(["**"]),
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.7.6",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "lexical_core",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"arrayvec",
|
||||
"correct",
|
||||
"default",
|
||||
"ryu",
|
||||
"static_assertions",
|
||||
"std",
|
||||
"table",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.7.6",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
":lexical_core_build_script",
|
||||
"@raze__arrayvec__0_5_2//:arrayvec",
|
||||
"@raze__bitflags__1_3_2//:bitflags",
|
||||
"@raze__cfg_if__1_0_0//:cfg_if",
|
||||
"@raze__ryu__1_0_5//:ryu",
|
||||
"@raze__static_assertions__1_1_0//:static_assertions",
|
||||
],
|
||||
)
|
162
cargo/remote/BUILD.nom-6.1.2.bazel
vendored
162
cargo/remote/BUILD.nom-6.1.2.bazel
vendored
|
@ -1,162 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
# buildifier: disable=out-of-order-load
|
||||
# buildifier: disable=load-on-top
|
||||
load(
|
||||
"@rules_rust//cargo:cargo_build_script.bzl",
|
||||
"cargo_build_script",
|
||||
)
|
||||
|
||||
cargo_build_script(
|
||||
name = "nom_build_script",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
build_script_env = {
|
||||
},
|
||||
crate_features = [
|
||||
"alloc",
|
||||
"bitvec",
|
||||
"default",
|
||||
"funty",
|
||||
"lexical",
|
||||
"lexical-core",
|
||||
"std",
|
||||
],
|
||||
crate_root = "build.rs",
|
||||
data = glob(["**"]),
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "6.1.2",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"@raze__version_check__0_9_3//:version_check",
|
||||
],
|
||||
)
|
||||
|
||||
# Unsupported target "arithmetic" with type "bench" omitted
|
||||
|
||||
# Unsupported target "http" with type "bench" omitted
|
||||
|
||||
# Unsupported target "ini" with type "bench" omitted
|
||||
|
||||
# Unsupported target "ini_complete" with type "bench" omitted
|
||||
|
||||
# Unsupported target "ini_str" with type "bench" omitted
|
||||
|
||||
# Unsupported target "json" with type "bench" omitted
|
||||
|
||||
# Unsupported target "number" with type "bench" omitted
|
||||
|
||||
# Unsupported target "json" with type "example" omitted
|
||||
|
||||
# Unsupported target "s_expression" with type "example" omitted
|
||||
|
||||
# Unsupported target "string" with type "example" omitted
|
||||
|
||||
rust_library(
|
||||
name = "nom",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"alloc",
|
||||
"bitvec",
|
||||
"default",
|
||||
"funty",
|
||||
"lexical",
|
||||
"lexical-core",
|
||||
"std",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "6.1.2",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
":nom_build_script",
|
||||
"@raze__bitvec__0_19_5//:bitvec",
|
||||
"@raze__funty__1_1_0//:funty",
|
||||
"@raze__lexical_core__0_7_6//:lexical_core",
|
||||
"@raze__memchr__2_4_1//:memchr",
|
||||
],
|
||||
)
|
||||
|
||||
# Unsupported target "arithmetic" with type "test" omitted
|
||||
|
||||
# Unsupported target "arithmetic_ast" with type "test" omitted
|
||||
|
||||
# Unsupported target "bitstream" with type "test" omitted
|
||||
|
||||
# Unsupported target "blockbuf-arithmetic" with type "test" omitted
|
||||
|
||||
# Unsupported target "css" with type "test" omitted
|
||||
|
||||
# Unsupported target "custom_errors" with type "test" omitted
|
||||
|
||||
# Unsupported target "escaped" with type "test" omitted
|
||||
|
||||
# Unsupported target "float" with type "test" omitted
|
||||
|
||||
# Unsupported target "fnmut" with type "test" omitted
|
||||
|
||||
# Unsupported target "inference" with type "test" omitted
|
||||
|
||||
# Unsupported target "ini" with type "test" omitted
|
||||
|
||||
# Unsupported target "ini_str" with type "test" omitted
|
||||
|
||||
# Unsupported target "issues" with type "test" omitted
|
||||
|
||||
# Unsupported target "json" with type "test" omitted
|
||||
|
||||
# Unsupported target "mp4" with type "test" omitted
|
||||
|
||||
# Unsupported target "multiline" with type "test" omitted
|
||||
|
||||
# Unsupported target "named_args" with type "test" omitted
|
||||
|
||||
# Unsupported target "overflow" with type "test" omitted
|
||||
|
||||
# Unsupported target "reborrow_fold" with type "test" omitted
|
||||
|
||||
# Unsupported target "test1" with type "test" omitted
|
2
cargo/remote/BUILD.num-traits-0.2.14.bazel
vendored
2
cargo/remote/BUILD.num-traits-0.2.14.bazel
vendored
|
@ -42,7 +42,6 @@ cargo_build_script(
|
|||
build_script_env = {
|
||||
},
|
||||
crate_features = [
|
||||
"default",
|
||||
"std",
|
||||
],
|
||||
crate_root = "build.rs",
|
||||
|
@ -66,7 +65,6 @@ rust_library(
|
|||
name = "num_traits",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"default",
|
||||
"std",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
|
|
2
cargo/remote/BUILD.pyo3-0.14.5.bazel
vendored
2
cargo/remote/BUILD.pyo3-0.14.5.bazel
vendored
|
@ -43,7 +43,6 @@ cargo_build_script(
|
|||
},
|
||||
crate_features = [
|
||||
"abi3",
|
||||
"abi3-py38",
|
||||
"abi3-py39",
|
||||
"default",
|
||||
"extension-module",
|
||||
|
@ -93,7 +92,6 @@ rust_library(
|
|||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"abi3",
|
||||
"abi3-py38",
|
||||
"abi3-py39",
|
||||
"default",
|
||||
"extension-module",
|
||||
|
|
|
@ -44,7 +44,6 @@ cargo_build_script(
|
|||
},
|
||||
crate_features = [
|
||||
"abi3",
|
||||
"abi3-py38",
|
||||
"abi3-py39",
|
||||
"default",
|
||||
"resolve-config",
|
||||
|
@ -70,7 +69,6 @@ rust_library(
|
|||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"abi3",
|
||||
"abi3-py38",
|
||||
"abi3-py39",
|
||||
"default",
|
||||
"resolve-config",
|
||||
|
|
83
cargo/remote/BUILD.radium-0.5.3.bazel
vendored
83
cargo/remote/BUILD.radium-0.5.3.bazel
vendored
|
@ -1,83 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
# buildifier: disable=out-of-order-load
|
||||
# buildifier: disable=load-on-top
|
||||
load(
|
||||
"@rules_rust//cargo:cargo_build_script.bzl",
|
||||
"cargo_build_script",
|
||||
)
|
||||
|
||||
cargo_build_script(
|
||||
name = "radium_build_script",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
build_script_env = {
|
||||
},
|
||||
crate_features = [
|
||||
],
|
||||
crate_root = "build.rs",
|
||||
data = glob(["**"]),
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.5.3",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "radium",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.5.3",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
":radium_build_script",
|
||||
],
|
||||
)
|
53
cargo/remote/BUILD.static_assertions-1.1.0.bazel
vendored
53
cargo/remote/BUILD.static_assertions-1.1.0.bazel
vendored
|
@ -1,53 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT OR Apache-2.0"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
rust_library(
|
||||
name = "static_assertions",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2015",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "1.1.0",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
],
|
||||
)
|
53
cargo/remote/BUILD.tap-1.0.1.bazel
vendored
53
cargo/remote/BUILD.tap-1.0.1.bazel
vendored
|
@ -1,53 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
rust_library(
|
||||
name = "tap",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2015",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "1.0.1",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
],
|
||||
)
|
54
cargo/remote/BUILD.wyz-0.2.0.bazel
vendored
54
cargo/remote/BUILD.wyz-0.2.0.bazel
vendored
|
@ -1,54 +0,0 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
rust_library(
|
||||
name = "wyz",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"alloc",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.2.0",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
],
|
||||
)
|
|
@ -9,12 +9,45 @@ import "anki/generic.proto";
|
|||
import "anki/cards.proto";
|
||||
|
||||
service StatsService {
|
||||
rpc CardStats(cards.CardId) returns (generic.String);
|
||||
rpc CardStats(cards.CardId) returns (CardStatsResponse);
|
||||
rpc Graphs(GraphsRequest) returns (GraphsResponse);
|
||||
rpc GetGraphPreferences(generic.Empty) returns (GraphPreferences);
|
||||
rpc SetGraphPreferences(GraphPreferences) returns (generic.Empty);
|
||||
}
|
||||
|
||||
message CardStatsResponse {
|
||||
message StatsRevlogEntry {
|
||||
int64 time = 1;
|
||||
RevlogEntry.ReviewKind review_kind = 2;
|
||||
uint32 button_chosen = 3;
|
||||
// seconds
|
||||
uint32 interval = 4;
|
||||
// per mill
|
||||
uint32 ease = 5;
|
||||
float taken_secs = 6;
|
||||
}
|
||||
repeated StatsRevlogEntry revlog = 1;
|
||||
int64 card_id = 2;
|
||||
int64 note_id = 3;
|
||||
string deck = 4;
|
||||
// Unix timestamps
|
||||
int64 added = 5;
|
||||
generic.Int64 first_review = 6;
|
||||
generic.Int64 latest_review = 7;
|
||||
generic.Int64 due_date = 8;
|
||||
generic.Int32 due_position = 9;
|
||||
// days
|
||||
uint32 interval = 10;
|
||||
// per mill
|
||||
uint32 ease = 11;
|
||||
uint32 reviews = 12;
|
||||
uint32 lapses = 13;
|
||||
float average_secs = 14;
|
||||
float total_secs = 15;
|
||||
string card_type = 16;
|
||||
string notetype = 17;
|
||||
}
|
||||
|
||||
message GraphsRequest {
|
||||
string search = 1;
|
||||
uint32 days = 2;
|
||||
|
|
|
@ -62,7 +62,13 @@ SKIP_UNROLL_INPUT = {
|
|||
}
|
||||
SKIP_UNROLL_OUTPUT = {"GetPreferences"}
|
||||
|
||||
SKIP_DECODE = {"Graphs", "GetGraphPreferences", "GetChangeNotetypeInfo", "CompleteTag"}
|
||||
SKIP_DECODE = {
|
||||
"Graphs",
|
||||
"GetGraphPreferences",
|
||||
"GetChangeNotetypeInfo",
|
||||
"CompleteTag",
|
||||
"CardStats",
|
||||
}
|
||||
|
||||
|
||||
def python_type(field):
|
||||
|
|
|
@ -24,6 +24,7 @@ SearchNode = search_pb2.SearchNode
|
|||
Progress = collection_pb2.Progress
|
||||
EmptyCardsReport = card_rendering_pb2.EmptyCardsReport
|
||||
GraphPreferences = stats_pb2.GraphPreferences
|
||||
CardStats = stats_pb2.CardStatsResponse
|
||||
Preferences = config_pb2.Preferences
|
||||
UndoStatus = collection_pb2.UndoStatus
|
||||
OpChanges = collection_pb2.OpChanges
|
||||
|
@ -807,23 +808,8 @@ class Collection(DeprecatedNamesMixin):
|
|||
|
||||
return CollectionStats(self)
|
||||
|
||||
def card_stats(self, card_id: CardId, include_revlog: bool) -> str:
|
||||
import anki.stats as st
|
||||
|
||||
if include_revlog:
|
||||
revlog_style = "margin-top: 2em;"
|
||||
else:
|
||||
revlog_style = "display: none;"
|
||||
|
||||
style = f"""<style>
|
||||
.revlog-learn {{ color: {st.colLearn} }}
|
||||
.revlog-review {{ color: {st.colMature} }}
|
||||
.revlog-relearn {{ color: {st.colRelearn} }}
|
||||
.revlog-ease1 {{ color: {st.colRelearn} }}
|
||||
table.review-log {{ {revlog_style} }}
|
||||
</style>"""
|
||||
|
||||
return style + self._backend.card_stats(card_id)
|
||||
def card_stats_data(self, card_id: CardId) -> bytes:
|
||||
return self._backend.card_stats(card_id)
|
||||
|
||||
def studied_today(self) -> str:
|
||||
return self._backend.studied_today()
|
||||
|
@ -1149,9 +1135,17 @@ table.review-log {{ {revlog_style} }}
|
|||
def _remNotes(self, ids: list[NoteId]) -> None:
|
||||
pass
|
||||
|
||||
@deprecated(replaced_by=card_stats)
|
||||
@deprecated(replaced_by=card_stats_data)
|
||||
def card_stats(self, card_id: CardId, include_revlog: bool) -> str:
|
||||
from anki.stats import _legacy_card_stats
|
||||
|
||||
return _legacy_card_stats(self, card_id, include_revlog)
|
||||
|
||||
@deprecated(replaced_by=card_stats_data)
|
||||
def cardStats(self, card: Card) -> str:
|
||||
return self.card_stats(card.id, include_revlog=False)
|
||||
from anki.stats import _legacy_card_stats
|
||||
|
||||
return _legacy_card_stats(self, card.id, False)
|
||||
|
||||
@deprecated(replaced_by=after_note_updates)
|
||||
def updateFieldCache(self, nids: list[NoteId]) -> None:
|
||||
|
|
|
@ -7,6 +7,7 @@ from __future__ import annotations
|
|||
|
||||
import datetime
|
||||
import json
|
||||
import random
|
||||
import time
|
||||
from typing import Sequence
|
||||
|
||||
|
@ -14,17 +15,36 @@ import anki.cards
|
|||
import anki.collection
|
||||
from anki.consts import *
|
||||
from anki.lang import FormatTimeSpan
|
||||
from anki.utils import ids2str
|
||||
from anki.utils import base62, ids2str
|
||||
|
||||
# Card stats
|
||||
##########################################################################
|
||||
|
||||
_legacy_nightmode = False
|
||||
|
||||
|
||||
def _legacy_card_stats(
|
||||
col: anki.collection.Collection, card_id: anki.cards.CardId, include_revlog: bool
|
||||
) -> str:
|
||||
"A quick hack to preserve compatibility with the old HTML string API."
|
||||
random_id = f"cardinfo-{base62(random.randint(0, 2 ** 64 - 1))}"
|
||||
return f"""
|
||||
<div id="{random_id}"></div>
|
||||
<script src="js/vendor/bootstrap.bundle.min.js"></script>
|
||||
<link href="pages/card-info-base.css" rel="stylesheet" />
|
||||
<link href="pages/card-info.css" rel="stylesheet" />
|
||||
<script src="pages/card-info.js"></script>
|
||||
<script>
|
||||
if ({1 if _legacy_nightmode else 0}) {{
|
||||
document.documentElement.className = "night-mode";
|
||||
}}
|
||||
anki.cardInfo(document.getElementById('{random_id}'), {card_id}, {include_revlog});
|
||||
</script>
|
||||
"""
|
||||
|
||||
|
||||
class CardStats:
|
||||
"""
|
||||
New code should just call collection.card_stats() directly - this class
|
||||
is only left around for backwards compatibility.
|
||||
"""
|
||||
"""Do not use - this class is only left around for backwards compatibility."""
|
||||
|
||||
def __init__(self, col: anki.collection.Collection, card: anki.cards.Card) -> None:
|
||||
if col:
|
||||
|
@ -33,7 +53,7 @@ class CardStats:
|
|||
self.txt = ""
|
||||
|
||||
def report(self, include_revlog: bool = False) -> str:
|
||||
return self.col.card_stats(self.card.id, include_revlog=include_revlog)
|
||||
return _legacy_card_stats(self.col, self.card.id, include_revlog)
|
||||
|
||||
# legacy
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
import os
|
||||
import tempfile
|
||||
|
||||
from anki.collection import CardStats
|
||||
from tests.shared import getEmptyCol
|
||||
|
||||
|
||||
|
@ -14,12 +15,15 @@ def test_stats():
|
|||
col.addNote(note)
|
||||
c = note.cards()[0]
|
||||
# card stats
|
||||
assert col.card_stats(c.id, include_revlog=True)
|
||||
card_stats = CardStats()
|
||||
card_stats.ParseFromString(col.card_stats_data(c.id))
|
||||
assert card_stats.note_id == note.id
|
||||
col.reset()
|
||||
c = col.sched.getCard()
|
||||
col.sched.answerCard(c, 3)
|
||||
col.sched.answerCard(c, 2)
|
||||
assert col.card_stats(c.id, include_revlog=True)
|
||||
card_stats.ParseFromString(col.card_stats_data(c.id))
|
||||
assert len(card_stats.revlog) == 2
|
||||
|
||||
|
||||
def test_graphs_empty():
|
||||
|
|
|
@ -4,36 +4,53 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import aqt
|
||||
from anki.cards import Card
|
||||
from anki.stats import CardStats
|
||||
from anki.cards import Card, CardId
|
||||
from aqt.qt import *
|
||||
from aqt.utils import disable_help_button, qconnect, restoreGeom, saveGeom
|
||||
from aqt.utils import (
|
||||
addCloseShortcut,
|
||||
disable_help_button,
|
||||
qconnect,
|
||||
restoreGeom,
|
||||
saveGeom,
|
||||
)
|
||||
from aqt.webview import AnkiWebView
|
||||
|
||||
|
||||
class CardInfoDialog(QDialog):
|
||||
TITLE = "browser card info"
|
||||
GEOMETRY_KEY = "revlog"
|
||||
silentlyClose = True
|
||||
|
||||
def __init__(self, parent: QWidget, mw: aqt.AnkiQt, card: Card) -> None:
|
||||
super().__init__(parent)
|
||||
disable_help_button(self)
|
||||
cs = CardStats(mw.col, card)
|
||||
info = cs.report(include_revlog=True)
|
||||
|
||||
l = QVBoxLayout()
|
||||
l.setContentsMargins(0, 0, 0, 0)
|
||||
w = AnkiWebView(title="browser card info")
|
||||
l.addWidget(w)
|
||||
w.stdHtml(info + "<p>", context=self)
|
||||
bb = QDialogButtonBox(QDialogButtonBox.Close)
|
||||
l.addWidget(bb)
|
||||
qconnect(bb.rejected, self.reject)
|
||||
self.setLayout(l)
|
||||
self.setWindowModality(Qt.WindowModal)
|
||||
self.resize(500, 400)
|
||||
restoreGeom(self, "revlog")
|
||||
self.mw = mw
|
||||
self._setup_ui(card.id)
|
||||
self.show()
|
||||
|
||||
def _setup_ui(self, card_id: CardId) -> None:
|
||||
self.setWindowModality(Qt.ApplicationModal)
|
||||
self.mw.garbage_collect_on_dialog_finish(self)
|
||||
disable_help_button(self)
|
||||
restoreGeom(self, self.GEOMETRY_KEY)
|
||||
addCloseShortcut(self)
|
||||
|
||||
self.web = AnkiWebView(title=self.TITLE)
|
||||
self.web.setVisible(False)
|
||||
self.web.load_ts_page("card-info")
|
||||
layout = QVBoxLayout()
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(self.web)
|
||||
buttons = QDialogButtonBox(QDialogButtonBox.Close)
|
||||
buttons.setContentsMargins(10, 0, 10, 10)
|
||||
layout.addWidget(buttons)
|
||||
qconnect(buttons.rejected, self.reject)
|
||||
self.setLayout(layout)
|
||||
|
||||
self.web.eval(
|
||||
f"anki.cardInfo(document.getElementById('main'), {card_id}, true);"
|
||||
)
|
||||
|
||||
def reject(self) -> None:
|
||||
saveGeom(self, "revlog")
|
||||
self.web = None
|
||||
saveGeom(self, self.GEOMETRY_KEY)
|
||||
return QDialog.reject(self)
|
||||
|
|
|
@ -5,6 +5,7 @@ _pages = [
|
|||
"congrats",
|
||||
"deck-options",
|
||||
"change-notetype",
|
||||
"card-info",
|
||||
]
|
||||
|
||||
[copy_files_into_group(
|
||||
|
|
|
@ -20,6 +20,7 @@ from waitress.server import create_server
|
|||
|
||||
import aqt
|
||||
from anki import hooks
|
||||
from anki.cards import CardId
|
||||
from anki.collection import GraphPreferences, OpChanges
|
||||
from anki.decks import UpdateDeckConfigs
|
||||
from anki.models import NotetypeNames
|
||||
|
@ -411,6 +412,10 @@ def complete_tag() -> bytes:
|
|||
return aqt.mw.col.tags.complete_tag(request.data)
|
||||
|
||||
|
||||
def card_stats() -> bytes:
|
||||
return aqt.mw.col.card_stats_data(CardId(int(request.data)))
|
||||
|
||||
|
||||
# these require a collection
|
||||
post_handlers = {
|
||||
"graphData": graph_data,
|
||||
|
@ -426,6 +431,7 @@ post_handlers = {
|
|||
"i18nResources": i18n_resources,
|
||||
"congratsInfo": congrats_info,
|
||||
"completeTag": complete_tag,
|
||||
"cardStats": card_stats,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -246,6 +246,7 @@ QTabWidget {{ background-color: {}; }}
|
|||
s.colCram = self.color(colors.SUSPENDED_BG)
|
||||
s.colSusp = self.color(colors.SUSPENDED_BG)
|
||||
s.colMature = self.color(colors.REVIEW_COUNT)
|
||||
s._legacy_nightmode = self._night_mode_preference
|
||||
|
||||
|
||||
theme_manager = ThemeManager()
|
||||
|
|
|
@ -45,7 +45,6 @@ _anki_compile_data = glob([
|
|||
]) + [
|
||||
"Cargo.toml", # prevents a warning about num_enum
|
||||
"//:buildinfo.txt",
|
||||
"templates/.empty", # required for askama
|
||||
]
|
||||
|
||||
_anki_features = [
|
||||
|
@ -73,7 +72,6 @@ rust_library(
|
|||
deps = [
|
||||
":build_script",
|
||||
"//rslib/cargo:ammonia",
|
||||
"//rslib/cargo:askama",
|
||||
"//rslib/cargo:blake3",
|
||||
"//rslib/cargo:bytes",
|
||||
"//rslib/cargo:chrono",
|
||||
|
|
|
@ -30,7 +30,6 @@ anki_i18n = { path="i18n" }
|
|||
nom = "7.0.0"
|
||||
proc-macro-nested = "0.1.7"
|
||||
slog-term = "2.8.0"
|
||||
askama = "0.10.5"
|
||||
blake3 = "1.0.0"
|
||||
bytes = "1.1.0"
|
||||
chrono = "0.4.19"
|
||||
|
|
|
@ -21,15 +21,6 @@ alias(
|
|||
],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "askama",
|
||||
actual = "@raze__askama__0_10_5//:askama",
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "async_trait",
|
||||
actual = "@raze__async_trait__0_1_51//:async_trait",
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
|
||||
use super::Backend;
|
||||
pub(super) use crate::backend_proto::stats_service::Service as StatsService;
|
||||
use crate::{backend_proto as pb, prelude::*};
|
||||
use crate::{backend_proto as pb, prelude::*, revlog::RevlogReviewKind};
|
||||
|
||||
impl StatsService for Backend {
|
||||
fn card_stats(&self, input: pb::CardId) -> Result<pb::String> {
|
||||
fn card_stats(&self, input: pb::CardId) -> Result<pb::CardStatsResponse> {
|
||||
self.with_col(|col| col.card_stats(input.into()))
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn graphs(&self, input: pb::GraphsRequest) -> Result<pb::GraphsResponse> {
|
||||
|
@ -24,3 +23,15 @@ impl StatsService for Backend {
|
|||
.map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RevlogReviewKind> for i32 {
|
||||
fn from(kind: RevlogReviewKind) -> Self {
|
||||
(match kind {
|
||||
RevlogReviewKind::Learning => pb::revlog_entry::ReviewKind::Learning,
|
||||
RevlogReviewKind::Review => pb::revlog_entry::ReviewKind::Review,
|
||||
RevlogReviewKind::Relearning => pb::revlog_entry::ReviewKind::Relearning,
|
||||
RevlogReviewKind::Filtered => pb::revlog_entry::ReviewKind::Filtered,
|
||||
RevlogReviewKind::Manual => pb::revlog_entry::ReviewKind::Manual,
|
||||
}) as i32
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,68 +1,10 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use askama::Template;
|
||||
use chrono::prelude::*;
|
||||
|
||||
use crate::{
|
||||
card::CardQueue,
|
||||
i18n::I18n,
|
||||
prelude::*,
|
||||
revlog::{RevlogEntry, RevlogReviewKind},
|
||||
scheduler::timespan::time_span,
|
||||
};
|
||||
|
||||
struct CardStats {
|
||||
added: TimestampSecs,
|
||||
first_review: Option<TimestampSecs>,
|
||||
latest_review: Option<TimestampSecs>,
|
||||
due: Due,
|
||||
interval_secs: u32,
|
||||
ease: u32,
|
||||
reviews: u32,
|
||||
lapses: u32,
|
||||
average_secs: f32,
|
||||
total_secs: f32,
|
||||
card_type: String,
|
||||
notetype: String,
|
||||
deck: String,
|
||||
nid: NoteId,
|
||||
cid: CardId,
|
||||
revlog: Vec<RevlogEntry>,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "../src/stats/card_stats.html")]
|
||||
struct CardStatsTemplate {
|
||||
stats: Vec<(String, String)>,
|
||||
revlog: Vec<RevlogText>,
|
||||
revlog_titles: RevlogText,
|
||||
}
|
||||
|
||||
enum Due {
|
||||
Time(TimestampSecs),
|
||||
Position(i32),
|
||||
Unknown,
|
||||
}
|
||||
|
||||
struct RevlogText {
|
||||
time: String,
|
||||
kind: String,
|
||||
kind_class: String,
|
||||
rating: String,
|
||||
rating_class: String,
|
||||
interval: String,
|
||||
ease: String,
|
||||
taken_secs: String,
|
||||
}
|
||||
use crate::{backend_proto as pb, card::CardQueue, prelude::*, revlog::RevlogEntry};
|
||||
|
||||
impl Collection {
|
||||
pub fn card_stats(&mut self, cid: CardId) -> Result<String> {
|
||||
let stats = self.gather_card_stats(cid)?;
|
||||
Ok(self.card_stats_to_string(stats))
|
||||
}
|
||||
|
||||
fn gather_card_stats(&mut self, cid: CardId) -> Result<CardStats> {
|
||||
pub fn card_stats(&mut self, cid: CardId) -> Result<pb::CardStatsResponse> {
|
||||
let card = self.storage.get_card(cid)?.ok_or(AnkiError::NotFound)?;
|
||||
let note = self
|
||||
.storage
|
||||
|
@ -75,184 +17,92 @@ impl Collection {
|
|||
.storage
|
||||
.get_deck(card.deck_id)?
|
||||
.ok_or(AnkiError::NotFound)?;
|
||||
|
||||
let revlog = self.storage.get_revlog_entries_for_card(card.id)?;
|
||||
let average_secs;
|
||||
let total_secs;
|
||||
let normal_answer_count = revlog.iter().filter(|r| r.button_chosen > 0).count();
|
||||
if normal_answer_count == 0 {
|
||||
average_secs = 0.0;
|
||||
total_secs = 0.0;
|
||||
} else {
|
||||
total_secs = revlog
|
||||
.iter()
|
||||
.map(|e| (e.taken_millis as f32) / 1000.0)
|
||||
.sum();
|
||||
average_secs = total_secs / normal_answer_count as f32;
|
||||
}
|
||||
|
||||
let due = if card.original_due != 0 {
|
||||
card.original_due
|
||||
} else {
|
||||
card.due
|
||||
};
|
||||
let due = match card.queue {
|
||||
CardQueue::New => Due::Position(due),
|
||||
CardQueue::Learn => Due::Time(TimestampSecs::now()),
|
||||
CardQueue::Review | CardQueue::DayLearn => Due::Time({
|
||||
let days_remaining = due - (self.timing_today()?.days_elapsed as i32);
|
||||
let mut due = TimestampSecs::now();
|
||||
due.0 += (days_remaining as i64) * 86_400;
|
||||
due
|
||||
let (average_secs, total_secs) = average_and_total_secs_strings(&revlog);
|
||||
let (due_date, due_position) = self.due_date_and_position_strings(&card)?;
|
||||
|
||||
Ok(pb::CardStatsResponse {
|
||||
card_id: card.id.into(),
|
||||
note_id: card.note_id.into(),
|
||||
deck: deck.human_name(),
|
||||
added: card.id.as_secs().0,
|
||||
first_review: revlog.first().map(|entry| pb::generic::Int64 {
|
||||
val: entry.id.as_secs().0,
|
||||
}),
|
||||
_ => Due::Unknown,
|
||||
};
|
||||
|
||||
Ok(CardStats {
|
||||
added: card.id.as_secs(),
|
||||
first_review: revlog.first().map(|e| e.id.as_secs()),
|
||||
latest_review: revlog.last().map(|e| e.id.as_secs()),
|
||||
due,
|
||||
interval_secs: card.interval * 86_400,
|
||||
ease: (card.ease_factor as u32) / 10,
|
||||
latest_review: revlog.last().map(|entry| pb::generic::Int64 {
|
||||
val: entry.id.as_secs().0,
|
||||
}),
|
||||
due_date,
|
||||
due_position,
|
||||
interval: card.interval,
|
||||
ease: card.ease_factor as u32,
|
||||
reviews: card.reps,
|
||||
lapses: card.lapses,
|
||||
average_secs,
|
||||
total_secs,
|
||||
card_type: nt.get_template(card.template_idx)?.name.clone(),
|
||||
notetype: nt.name.clone(),
|
||||
deck: deck.human_name(),
|
||||
nid: card.note_id,
|
||||
cid: card.id,
|
||||
revlog: revlog.into_iter().map(Into::into).collect(),
|
||||
revlog: revlog
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|entry| stats_revlog_entry(entry))
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
fn card_stats_to_string(&mut self, cs: CardStats) -> String {
|
||||
let tr = &self.tr;
|
||||
|
||||
let mut stats = vec![(tr.card_stats_added().into(), cs.added.date_string())];
|
||||
if let Some(first) = cs.first_review {
|
||||
stats.push((tr.card_stats_first_review().into(), first.date_string()))
|
||||
}
|
||||
if let Some(last) = cs.latest_review {
|
||||
stats.push((tr.card_stats_latest_review().into(), last.date_string()))
|
||||
}
|
||||
|
||||
match cs.due {
|
||||
Due::Time(secs) => {
|
||||
stats.push((tr.statistics_due_date().into(), secs.date_string()));
|
||||
}
|
||||
Due::Position(pos) => {
|
||||
stats.push((tr.card_stats_new_card_position().into(), pos.to_string()));
|
||||
}
|
||||
Due::Unknown => {}
|
||||
fn due_date_and_position_strings(
|
||||
&mut self,
|
||||
card: &Card,
|
||||
) -> Result<(Option<pb::generic::Int64>, Option<pb::generic::Int32>)> {
|
||||
let due = if card.original_due != 0 {
|
||||
card.original_due
|
||||
} else {
|
||||
card.due
|
||||
};
|
||||
|
||||
if cs.interval_secs > 0 {
|
||||
stats.push((
|
||||
tr.card_stats_interval().into(),
|
||||
time_span(cs.interval_secs as f32, tr, true),
|
||||
));
|
||||
}
|
||||
|
||||
if cs.ease > 0 {
|
||||
stats.push((tr.card_stats_ease().into(), format!("{}%", cs.ease)));
|
||||
}
|
||||
stats.push((tr.card_stats_review_count().into(), cs.reviews.to_string()));
|
||||
stats.push((tr.card_stats_lapse_count().into(), cs.lapses.to_string()));
|
||||
|
||||
if cs.total_secs > 0.0 {
|
||||
stats.push((
|
||||
tr.card_stats_average_time().into(),
|
||||
time_span(cs.average_secs, tr, true),
|
||||
));
|
||||
stats.push((
|
||||
tr.card_stats_total_time().into(),
|
||||
time_span(cs.total_secs, tr, true),
|
||||
));
|
||||
}
|
||||
|
||||
stats.push((tr.card_stats_card_template().into(), cs.card_type));
|
||||
stats.push((tr.card_stats_note_type().into(), cs.notetype));
|
||||
stats.push((tr.card_stats_deck_name().into(), cs.deck));
|
||||
stats.push((tr.card_stats_card_id().into(), cs.cid.0.to_string()));
|
||||
stats.push((tr.card_stats_note_id().into(), cs.nid.0.to_string()));
|
||||
|
||||
let revlog = cs
|
||||
.revlog
|
||||
.into_iter()
|
||||
.rev()
|
||||
.map(|e| revlog_to_text(e, tr))
|
||||
.collect();
|
||||
let revlog_titles = RevlogText {
|
||||
time: tr.card_stats_review_log_date().into(),
|
||||
kind: tr.card_stats_review_log_type().into(),
|
||||
kind_class: "".to_string(),
|
||||
rating: tr.card_stats_review_log_rating().into(),
|
||||
interval: tr.card_stats_interval().into(),
|
||||
ease: tr.card_stats_ease().into(),
|
||||
rating_class: "".to_string(),
|
||||
taken_secs: tr.card_stats_review_log_time_taken().into(),
|
||||
};
|
||||
|
||||
CardStatsTemplate {
|
||||
stats,
|
||||
revlog,
|
||||
revlog_titles,
|
||||
}
|
||||
.render()
|
||||
.unwrap()
|
||||
Ok(match card.queue {
|
||||
CardQueue::New => (None, Some(pb::generic::Int32 { val: due })),
|
||||
CardQueue::Learn => (
|
||||
Some(pb::generic::Int64 {
|
||||
val: TimestampSecs::now().0,
|
||||
}),
|
||||
None,
|
||||
),
|
||||
CardQueue::Review | CardQueue::DayLearn => (
|
||||
{
|
||||
let days_remaining = due - (self.timing_today()?.days_elapsed as i32);
|
||||
let mut due = TimestampSecs::now();
|
||||
due.0 += (days_remaining as i64) * 86_400;
|
||||
Some(pb::generic::Int64 { val: due.0 })
|
||||
},
|
||||
None,
|
||||
),
|
||||
_ => (None, None),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn revlog_to_text(e: RevlogEntry, tr: &I18n) -> RevlogText {
|
||||
let dt = Local.timestamp(e.id.as_secs().0, 0);
|
||||
let time = dt.format("<b>%Y-%m-%d</b> @ %H:%M").to_string();
|
||||
let kind = match e.review_kind {
|
||||
RevlogReviewKind::Learning => tr.card_stats_review_log_type_learn().into(),
|
||||
RevlogReviewKind::Review => tr.card_stats_review_log_type_review().into(),
|
||||
RevlogReviewKind::Relearning => tr.card_stats_review_log_type_relearn().into(),
|
||||
RevlogReviewKind::Filtered => tr.card_stats_review_log_type_filtered().into(),
|
||||
RevlogReviewKind::Manual => tr.card_stats_review_log_type_manual().into(),
|
||||
};
|
||||
let kind_class = match e.review_kind {
|
||||
RevlogReviewKind::Learning => String::from("revlog-learn"),
|
||||
RevlogReviewKind::Review => String::from("revlog-review"),
|
||||
RevlogReviewKind::Relearning => String::from("revlog-relearn"),
|
||||
RevlogReviewKind::Filtered => String::from("revlog-filtered"),
|
||||
RevlogReviewKind::Manual => String::from("revlog-manual"),
|
||||
};
|
||||
let rating = e.button_chosen.to_string();
|
||||
let interval = if e.interval == 0 {
|
||||
String::from("")
|
||||
fn average_and_total_secs_strings(revlog: &[RevlogEntry]) -> (f32, f32) {
|
||||
let normal_answer_count = revlog.iter().filter(|r| r.button_chosen > 0).count();
|
||||
let total_secs: f32 = revlog
|
||||
.iter()
|
||||
.map(|entry| (entry.taken_millis as f32) / 1000.0)
|
||||
.sum();
|
||||
if normal_answer_count == 0 || total_secs == 0.0 {
|
||||
(0.0, 0.0)
|
||||
} else {
|
||||
let interval_secs = e.interval_secs();
|
||||
time_span(interval_secs as f32, tr, true)
|
||||
};
|
||||
let ease = if e.ease_factor > 0 {
|
||||
format!("{}%", e.ease_factor / 10)
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
let rating_class = if e.button_chosen == 1 {
|
||||
String::from("revlog-ease1")
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
let taken_secs = tr
|
||||
.statistics_seconds_taken((e.taken_millis / 1000) as i32)
|
||||
.into();
|
||||
(total_secs / normal_answer_count as f32, total_secs)
|
||||
}
|
||||
}
|
||||
|
||||
RevlogText {
|
||||
time,
|
||||
kind,
|
||||
kind_class,
|
||||
rating,
|
||||
rating_class,
|
||||
interval,
|
||||
ease,
|
||||
taken_secs,
|
||||
fn stats_revlog_entry(entry: &RevlogEntry) -> pb::card_stats_response::StatsRevlogEntry {
|
||||
pb::card_stats_response::StatsRevlogEntry {
|
||||
time: entry.id.as_secs().0,
|
||||
review_kind: entry.review_kind.into(),
|
||||
button_chosen: entry.button_chosen as u32,
|
||||
interval: entry.interval_secs(),
|
||||
ease: entry.ease_factor,
|
||||
taken_secs: entry.taken_millis as f32 / 1000.,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
<table class="card-stats" width="100%">
|
||||
{% for row in stats %}
|
||||
<tr>
|
||||
<td align="left" style="padding-right: 3px;">
|
||||
<b>{{ row.0 }}</b>
|
||||
</td>
|
||||
<td>{{ row.1 }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% if !revlog.is_empty() %}
|
||||
<table class="review-log" width="100%">
|
||||
<tr>
|
||||
<th>{{ revlog_titles.time }}</th>
|
||||
<th align="right">{{ revlog_titles.kind }}</th>
|
||||
<th align="center">{{ revlog_titles.rating }}</th>
|
||||
<th>{{ revlog_titles.interval }}</th>
|
||||
<th align="right">{{ revlog_titles.ease }}</th>
|
||||
<th align="right">{{ revlog_titles.taken_secs }}</th>
|
||||
</tr>
|
||||
|
||||
{% for entry in revlog %}
|
||||
<tr>
|
||||
<td>{{ entry.time|safe }}</td>
|
||||
<td align="right" class="{{ entry.kind_class }}">{{ entry.kind }}</td>
|
||||
<td align="center" class="{{ entry.rating_class }}">{{ entry.rating }}</td>
|
||||
<td>{{ entry.interval }}</td>
|
||||
<td align="right">{{ entry.ease }}</td>
|
||||
<td align="right">{{ entry.taken_secs }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
69
ts/card-info/BUILD.bazel
Normal file
69
ts/card-info/BUILD.bazel
Normal file
|
@ -0,0 +1,69 @@
|
|||
load("//ts:prettier.bzl", "prettier_test")
|
||||
load("//ts:eslint.bzl", "eslint_test")
|
||||
load("//ts/svelte:svelte.bzl", "compile_svelte", "svelte_check")
|
||||
load("//ts:esbuild.bzl", "esbuild")
|
||||
load("//ts:compile_sass.bzl", "compile_sass")
|
||||
load("//ts:typescript.bzl", "typescript")
|
||||
|
||||
compile_sass(
|
||||
srcs = ["card-info-base.scss"],
|
||||
group = "base_css",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//sass:base_lib",
|
||||
"//sass:scrollbar_lib",
|
||||
"//sass/bootstrap",
|
||||
],
|
||||
)
|
||||
|
||||
compile_svelte()
|
||||
|
||||
typescript(
|
||||
name = "index",
|
||||
deps = [
|
||||
":svelte",
|
||||
"//ts/components",
|
||||
"//ts/lib",
|
||||
"@npm//@fluent",
|
||||
],
|
||||
)
|
||||
|
||||
esbuild(
|
||||
name = "card-info",
|
||||
args = {
|
||||
"globalName": "anki",
|
||||
"loader": {".svg": "text"},
|
||||
},
|
||||
entry_point = "index.ts",
|
||||
output_css = "card-info.css",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":base_css",
|
||||
":index",
|
||||
":svelte",
|
||||
"//ts/components",
|
||||
"//ts/lib",
|
||||
"@npm//protobufjs",
|
||||
],
|
||||
)
|
||||
|
||||
exports_files(["card-info.html"])
|
||||
|
||||
# Tests
|
||||
################
|
||||
|
||||
prettier_test()
|
||||
|
||||
eslint_test()
|
||||
|
||||
svelte_check(
|
||||
name = "svelte_check",
|
||||
srcs = glob([
|
||||
"*.ts",
|
||||
"*.svelte",
|
||||
]) + [
|
||||
"//sass:button_mixins_lib",
|
||||
"//sass/bootstrap",
|
||||
"//ts/components",
|
||||
],
|
||||
)
|
110
ts/card-info/CardInfo.svelte
Normal file
110
ts/card-info/CardInfo.svelte
Normal file
|
@ -0,0 +1,110 @@
|
|||
<!--
|
||||
Copyright: Ankitects Pty Ltd and contributors
|
||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
-->
|
||||
<script lang="ts">
|
||||
import * as tr2 from "../lib/ftl";
|
||||
import { Stats, unwrapOptionalNumber } from "../lib/proto";
|
||||
import { Timestamp, timeSpan, DAY } from "../lib/time";
|
||||
import Revlog from "./Revlog.svelte";
|
||||
|
||||
export let stats: Stats.CardStatsResponse;
|
||||
|
||||
function dateString(timestamp: number): string {
|
||||
return new Timestamp(timestamp).dateString();
|
||||
}
|
||||
|
||||
interface StatsRow {
|
||||
label: string;
|
||||
value: string | number;
|
||||
}
|
||||
|
||||
const statsRows: StatsRow[] = [];
|
||||
|
||||
statsRows.push({ label: tr2.cardStatsAdded(), value: dateString(stats.added) });
|
||||
|
||||
const firstReview = unwrapOptionalNumber(stats.firstReview);
|
||||
if (firstReview !== undefined) {
|
||||
statsRows.push({
|
||||
label: tr2.cardStatsFirstReview(),
|
||||
value: dateString(firstReview),
|
||||
});
|
||||
}
|
||||
const latestReview = unwrapOptionalNumber(stats.latestReview);
|
||||
if (latestReview !== undefined) {
|
||||
statsRows.push({
|
||||
label: tr2.cardStatsLatestReview(),
|
||||
value: dateString(latestReview),
|
||||
});
|
||||
}
|
||||
|
||||
const dueDate = unwrapOptionalNumber(stats.dueDate);
|
||||
if (dueDate !== undefined) {
|
||||
statsRows.push({ label: tr2.statisticsDueDate(), value: dateString(dueDate) });
|
||||
}
|
||||
const duePosition = unwrapOptionalNumber(stats.duePosition);
|
||||
if (duePosition !== undefined) {
|
||||
statsRows.push({
|
||||
label: tr2.cardStatsNewCardPosition(),
|
||||
value: dateString(duePosition),
|
||||
});
|
||||
}
|
||||
|
||||
if (stats.interval) {
|
||||
statsRows.push({
|
||||
label: tr2.cardStatsInterval(),
|
||||
value: timeSpan(stats.interval * DAY),
|
||||
});
|
||||
}
|
||||
if (stats.ease) {
|
||||
statsRows.push({ label: tr2.cardStatsEase(), value: `${stats.ease / 10}%` });
|
||||
}
|
||||
|
||||
statsRows.push({ label: tr2.cardStatsReviewCount(), value: stats.reviews });
|
||||
statsRows.push({ label: tr2.cardStatsLapseCount(), value: stats.lapses });
|
||||
|
||||
if (stats.totalSecs) {
|
||||
statsRows.push({
|
||||
label: tr2.cardStatsAverageTime(),
|
||||
value: timeSpan(stats.averageSecs),
|
||||
});
|
||||
statsRows.push({
|
||||
label: tr2.cardStatsTotalTime(),
|
||||
value: timeSpan(stats.totalSecs),
|
||||
});
|
||||
}
|
||||
|
||||
statsRows.push({ label: tr2.cardStatsCardTemplate(), value: stats.cardType });
|
||||
statsRows.push({ label: tr2.cardStatsNoteType(), value: stats.notetype });
|
||||
statsRows.push({ label: tr2.cardStatsDeckName(), value: stats.deck });
|
||||
|
||||
statsRows.push({ label: tr2.cardStatsCardId(), value: stats.cardId });
|
||||
statsRows.push({ label: tr2.cardStatsNoteId(), value: stats.noteId });
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<div>
|
||||
<table class="stats-table">
|
||||
{#each statsRows as row, _index}
|
||||
<tr>
|
||||
<th style="text-align:start">{row.label}</th>
|
||||
<td>{row.value}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
<Revlog {stats} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.stats-table {
|
||||
width: 100%;
|
||||
text-align: start;
|
||||
}
|
||||
</style>
|
141
ts/card-info/Revlog.svelte
Normal file
141
ts/card-info/Revlog.svelte
Normal file
|
@ -0,0 +1,141 @@
|
|||
<!--
|
||||
Copyright: Ankitects Pty Ltd and contributors
|
||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
-->
|
||||
<script lang="ts">
|
||||
import * as tr2 from "../lib/ftl";
|
||||
import { Stats } from "../lib/proto";
|
||||
import { Timestamp, timeSpan } from "../lib/time";
|
||||
|
||||
export let stats: Stats.CardStatsResponse;
|
||||
|
||||
type IStatsRevlogEntry = Stats.CardStatsResponse.IStatsRevlogEntry;
|
||||
|
||||
function reviewKindClass(entry: IStatsRevlogEntry): string {
|
||||
switch (entry.reviewKind) {
|
||||
case Stats.RevlogEntry.ReviewKind.LEARNING:
|
||||
return "revlog-learn";
|
||||
case Stats.RevlogEntry.ReviewKind.REVIEW:
|
||||
return "revlog-review";
|
||||
case Stats.RevlogEntry.ReviewKind.RELEARNING:
|
||||
return "revlog-relearn";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function reviewKindLabel(entry: IStatsRevlogEntry): string {
|
||||
switch (entry.reviewKind) {
|
||||
case Stats.RevlogEntry.ReviewKind.LEARNING:
|
||||
return tr2.cardStatsReviewLogTypeLearn();
|
||||
case Stats.RevlogEntry.ReviewKind.REVIEW:
|
||||
return tr2.cardStatsReviewLogTypeReview();
|
||||
case Stats.RevlogEntry.ReviewKind.RELEARNING:
|
||||
return tr2.cardStatsReviewLogTypeRelearn();
|
||||
case Stats.RevlogEntry.ReviewKind.FILTERED:
|
||||
return tr2.cardStatsReviewLogTypeFiltered();
|
||||
case Stats.RevlogEntry.ReviewKind.MANUAL:
|
||||
return tr2.cardStatsReviewLogTypeManual();
|
||||
}
|
||||
}
|
||||
|
||||
function ratingClass(entry: IStatsRevlogEntry): string {
|
||||
if (entry.buttonChosen === 1) {
|
||||
return "revlog-ease1";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
interface RevlogRow {
|
||||
date: string;
|
||||
time: string;
|
||||
reviewKind: string;
|
||||
reviewKindClass: string;
|
||||
rating: number;
|
||||
ratingClass: string;
|
||||
interval: string;
|
||||
ease: string;
|
||||
takenSecs: string;
|
||||
}
|
||||
|
||||
function revlogRowFromEntry(entry: IStatsRevlogEntry): RevlogRow {
|
||||
const timestamp = new Timestamp(entry.time!);
|
||||
return {
|
||||
date: timestamp.dateString(),
|
||||
time: timestamp.timeString(),
|
||||
reviewKind: reviewKindLabel(entry),
|
||||
reviewKindClass: reviewKindClass(entry),
|
||||
rating: entry.buttonChosen!,
|
||||
ratingClass: ratingClass(entry),
|
||||
interval: timeSpan(entry.interval!),
|
||||
ease: entry.ease ? `${entry.ease / 10}%` : "",
|
||||
takenSecs: timeSpan(entry.takenSecs!, true),
|
||||
};
|
||||
}
|
||||
|
||||
const revlogRows: RevlogRow[] = stats.revlog.map((entry) =>
|
||||
revlogRowFromEntry(entry)
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if stats.revlog.length}
|
||||
<div class="revlog-container">
|
||||
<table class="revlog-table">
|
||||
<tr>
|
||||
<th>{tr2.cardStatsReviewLogDate()}</th>
|
||||
<th>{tr2.cardStatsReviewLogType()}</th>
|
||||
<th>{tr2.cardStatsReviewLogRating()}</th>
|
||||
<th>{tr2.cardStatsInterval()}</th>
|
||||
<th>{tr2.cardStatsEase()}</th>
|
||||
<th>{tr2.cardStatsReviewLogTimeTaken()}</th>
|
||||
</tr>
|
||||
{#each revlogRows as row, _index}
|
||||
<tr>
|
||||
<td class="left"><b>{row.date}</b> @ {row.time}</td>
|
||||
<td class="center {row.reviewKindClass}">
|
||||
{row.reviewKind}
|
||||
</td>
|
||||
<td class="center {row.ratingClass}">{row.rating}</td>
|
||||
<td class="center">{row.interval}</td>
|
||||
<td class="center">{row.ease}</td>
|
||||
<td class="right">{row.takenSecs}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.left {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.right {
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.revlog-container {
|
||||
margin: 4em -2em 0 -2em;
|
||||
}
|
||||
|
||||
.revlog-table {
|
||||
width: 100%;
|
||||
border-spacing: 2em 0em;
|
||||
}
|
||||
|
||||
.revlog-learn {
|
||||
color: var(--new-count);
|
||||
}
|
||||
|
||||
.revlog-review {
|
||||
color: var(--review-count);
|
||||
}
|
||||
|
||||
.revlog-relearn,
|
||||
.revlog-ease1 {
|
||||
color: var(--learn-count);
|
||||
}
|
||||
</style>
|
6
ts/card-info/card-info-base.scss
Normal file
6
ts/card-info/card-info-base.scss
Normal file
|
@ -0,0 +1,6 @@
|
|||
@use "core";
|
||||
@use "scrollbar";
|
||||
|
||||
.night-mode {
|
||||
@include scrollbar.night-mode;
|
||||
}
|
14
ts/card-info/card-info.html
Normal file
14
ts/card-info/card-info.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" id="viewport" content="width=device-width" />
|
||||
<link href="card-info-base.css" rel="stylesheet" />
|
||||
<link href="card-info.css" rel="stylesheet" />
|
||||
<script src="../js/vendor/bootstrap.bundle.min.js"></script>
|
||||
<script src="card-info.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main"></div>
|
||||
</body>
|
||||
</html>
|
33
ts/card-info/index.ts
Normal file
33
ts/card-info/index.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import { getCardStats } from "./lib";
|
||||
import { setupI18n, ModuleName } from "../lib/i18n";
|
||||
import { checkNightMode } from "../lib/nightmode";
|
||||
|
||||
import CardInfo from "./CardInfo.svelte";
|
||||
|
||||
export async function cardInfo(
|
||||
target: HTMLDivElement,
|
||||
cardId: number,
|
||||
includeRevlog: boolean
|
||||
): Promise<CardInfo> {
|
||||
checkNightMode();
|
||||
const [stats] = await Promise.all([
|
||||
getCardStats(cardId),
|
||||
setupI18n({
|
||||
modules: [
|
||||
ModuleName.CARD_STATS,
|
||||
ModuleName.SCHEDULING,
|
||||
ModuleName.STATISTICS,
|
||||
],
|
||||
}),
|
||||
]);
|
||||
if (!includeRevlog) {
|
||||
stats.revlog = [];
|
||||
}
|
||||
return new CardInfo({
|
||||
target,
|
||||
props: { stats },
|
||||
});
|
||||
}
|
11
ts/card-info/lib.ts
Normal file
11
ts/card-info/lib.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import { Stats } from "../lib/proto";
|
||||
import { postRequest } from "../lib/postrequest";
|
||||
|
||||
export async function getCardStats(cardId: number): Promise<Stats.CardStatsResponse> {
|
||||
return Stats.CardStatsResponse.decode(
|
||||
await postRequest("/_anki/cardStats", JSON.stringify(cardId))
|
||||
);
|
||||
}
|
5
ts/card-info/tsconfig.json
Normal file
5
ts/card-info/tsconfig.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"include": ["*"],
|
||||
"references": [{ "path": "../lib" }]
|
||||
}
|
|
@ -5,9 +5,28 @@ import { anki } from "./backend_proto";
|
|||
|
||||
import Cards = anki.cards;
|
||||
import DeckConfig = anki.deckconfig;
|
||||
import Generic = anki.generic;
|
||||
import Notetypes = anki.notetypes;
|
||||
import Scheduler = anki.scheduler;
|
||||
import Stats = anki.stats;
|
||||
import Tags = anki.tags;
|
||||
|
||||
export { Stats, Cards, DeckConfig, Notetypes, Scheduler, Tags };
|
||||
|
||||
export function unwrapOptionalNumber(
|
||||
msg:
|
||||
| Generic.IInt64
|
||||
| Generic.IUInt32
|
||||
| Generic.IInt32
|
||||
| Generic.OptionalInt32
|
||||
| Generic.OptionalUInt32
|
||||
| null
|
||||
| undefined
|
||||
): number | undefined {
|
||||
if (msg && msg !== null) {
|
||||
if (msg.val !== null) {
|
||||
return msg.val;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -177,3 +177,27 @@ export function dayLabel(daysStart: number, daysEnd: number): string {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Helper for converting Unix timestamps to date strings. */
|
||||
export class Timestamp {
|
||||
private date: Date;
|
||||
|
||||
constructor(seconds: number) {
|
||||
this.date = new Date(seconds * 1000);
|
||||
}
|
||||
|
||||
/** YYYY-MM-DD */
|
||||
dateString(): string {
|
||||
const year = this.date.getFullYear();
|
||||
const month = ("0" + (this.date.getMonth() + 1)).slice(-2);
|
||||
const date = ("0" + this.date.getDate()).slice(-2);
|
||||
return `${year}-${month}-${date}`;
|
||||
}
|
||||
|
||||
/** HH:MM */
|
||||
timeString(): string {
|
||||
const hours = ("0" + this.date.getHours()).slice(-2);
|
||||
const minutes = ("0" + this.date.getMinutes()).slice(-2);
|
||||
return `${hours}:${minutes}`;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue