mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
refactor protobuf handling for split/import
In order to split backend.proto into a more manageable size, the protobuf handling needed to be updated. This took more time than I would have liked, as each language handles protobuf differently: - The Python Protobuf code ignores "package" directives, and relies solely on how the files are laid out on disk. While it would have been nice to keep the generated files in a private subpackage, Protobuf gets confused if the files are located in a location that does not match their original .proto layout, so the old approach of storing them in _backend/ will not work. They now clutter up pylib/anki instead. I'm rather annoyed by that, but alternatives seem to be having to add an extra level to the Protobuf path, making the other languages suffer, or trying to hack around the issue by munging sys.modules. - Protobufjs fails to expose packages if they don't start with a capital letter, despite the fact that lowercase packages are the norm in most languages :-( This required a patch to fix. - Rust was the easiest, as Prost is relatively straightforward compared to Google's tools. The Protobuf files are now stored in /proto/anki, with a separate package for each file. I've split backend.proto into a few files as a test, but the majority of that work is still to come. The Python Protobuf building is a bit of a hack at the moment, hard-coding "proto" as the top level folder, but it seems to get the job done for now. Also changed the workspace name, as there seems to be a number of Bazel repos moving away from the more awkward reverse DNS naming style.
This commit is contained in:
parent
1d4b58419e
commit
616db33c0e
81 changed files with 516 additions and 467 deletions
|
@ -1,5 +1,5 @@
|
||||||
workspace(
|
workspace(
|
||||||
name = "net_ankiweb_anki",
|
name = "anki",
|
||||||
managed_directories = {"@npm": [
|
managed_directories = {"@npm": [
|
||||||
"ts/node_modules",
|
"ts/node_modules",
|
||||||
]},
|
]},
|
||||||
|
|
10
defs.bzl
10
defs.bzl
|
@ -1,7 +1,7 @@
|
||||||
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
|
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
|
||||||
load("@bazel_skylib//lib:versions.bzl", "versions")
|
load("@bazel_skylib//lib:versions.bzl", "versions")
|
||||||
load("@rules_rust//rust:repositories.bzl", "rust_repositories")
|
load("@rules_rust//rust:repositories.bzl", "rust_repositories")
|
||||||
load("@net_ankiweb_anki//cargo:crates.bzl", "raze_fetch_remote_crates")
|
load("@anki//cargo:crates.bzl", "raze_fetch_remote_crates")
|
||||||
load(":python.bzl", "setup_local_python")
|
load(":python.bzl", "setup_local_python")
|
||||||
load(":protobuf.bzl", "setup_protobuf_binary")
|
load(":protobuf.bzl", "setup_protobuf_binary")
|
||||||
load("//proto:format.bzl", "setup_clang_format")
|
load("//proto:format.bzl", "setup_clang_format")
|
||||||
|
@ -35,7 +35,7 @@ def setup_deps():
|
||||||
|
|
||||||
pip_import(
|
pip_import(
|
||||||
name = "py_deps",
|
name = "py_deps",
|
||||||
requirements = "@net_ankiweb_anki//pip:requirements.txt",
|
requirements = "@anki//pip:requirements.txt",
|
||||||
python_runtime = "@python//:python",
|
python_runtime = "@python//:python",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,12 +44,12 @@ def setup_deps():
|
||||||
python_runtime = "@python//:python",
|
python_runtime = "@python//:python",
|
||||||
)
|
)
|
||||||
|
|
||||||
node_repositories(package_json = ["@net_ankiweb_anki//ts:package.json"])
|
node_repositories(package_json = ["@anki//ts:package.json"])
|
||||||
|
|
||||||
yarn_install(
|
yarn_install(
|
||||||
name = "npm",
|
name = "npm",
|
||||||
package_json = "@net_ankiweb_anki//ts:package.json",
|
package_json = "@anki//ts:package.json",
|
||||||
yarn_lock = "@net_ankiweb_anki//ts:yarn.lock",
|
yarn_lock = "@anki//ts:yarn.lock",
|
||||||
)
|
)
|
||||||
|
|
||||||
sass_repositories()
|
sass_repositories()
|
||||||
|
|
|
@ -74,14 +74,14 @@ index eff3d9df2..fb2e9f7fe 100644
|
||||||
python_runtime = "@python//:python",
|
python_runtime = "@python//:python",
|
||||||
)
|
)
|
||||||
|
|
||||||
- node_repositories(package_json = ["@net_ankiweb_anki//ts:package.json"])
|
- node_repositories(package_json = ["@anki//ts:package.json"])
|
||||||
+ native.local_repository(
|
+ native.local_repository(
|
||||||
+ name = "local_node",
|
+ name = "local_node",
|
||||||
+ path = "local_node",
|
+ path = "local_node",
|
||||||
+ )
|
+ )
|
||||||
+
|
+
|
||||||
+ node_repositories(
|
+ node_repositories(
|
||||||
+ package_json = ["@net_ankiweb_anki//ts:package.json"],
|
+ package_json = ["@anki//ts:package.json"],
|
||||||
+ vendored_node = "@local_node//:node",
|
+ vendored_node = "@local_node//:node",
|
||||||
+ )
|
+ )
|
||||||
|
|
||||||
|
|
0
proto/.top_level
Normal file
0
proto/.top_level
Normal file
|
@ -6,13 +6,27 @@ load("//proto:clang_format.bzl", "proto_format")
|
||||||
|
|
||||||
proto_format(
|
proto_format(
|
||||||
name = "format",
|
name = "format",
|
||||||
srcs = ["backend.proto"],
|
srcs = glob(["**/*.proto"]),
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
proto_library(
|
proto_library(
|
||||||
name = "backend_proto_lib",
|
name = "backend_proto_lib",
|
||||||
srcs = ["backend.proto"],
|
srcs = glob(["**/*.proto"]),
|
||||||
|
# "" removes the "proto/" prefix
|
||||||
|
strip_import_prefix = "",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
exports_files(["backend.proto"])
|
filegroup(
|
||||||
|
name = "proto",
|
||||||
|
srcs = glob(["**/*.proto"]),
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
exports_files([
|
||||||
|
# for external workspace use
|
||||||
|
"format.py",
|
||||||
|
# an empty file we use to get the root proto/ path in the Rust build
|
||||||
|
".top_level",
|
||||||
|
])
|
||||||
|
|
|
@ -1,59 +1,11 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package BackendProto;
|
package anki.backend;
|
||||||
|
|
||||||
// Generic containers
|
import "anki/generic.proto";
|
||||||
///////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
message Empty {}
|
|
||||||
|
|
||||||
message OptionalInt32 {
|
|
||||||
sint32 val = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message OptionalUInt32 {
|
|
||||||
uint32 val = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Int32 {
|
|
||||||
sint32 val = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message UInt32 {
|
|
||||||
uint32 val = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Int64 {
|
|
||||||
int64 val = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message String {
|
|
||||||
string val = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Json {
|
|
||||||
bytes json = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Bool {
|
|
||||||
bool val = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message StringList {
|
|
||||||
repeated string vals = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message OpChangesWithCount {
|
|
||||||
uint32 count = 1;
|
|
||||||
OpChanges changes = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message OpChangesWithId {
|
|
||||||
int64 id = 1;
|
|
||||||
OpChanges changes = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IDs used in RPC calls
|
// IDs used in RPC calls
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
@ -115,13 +67,13 @@ enum ServiceIndex {
|
||||||
}
|
}
|
||||||
|
|
||||||
service SchedulingService {
|
service SchedulingService {
|
||||||
rpc SchedTimingToday(Empty) returns (SchedTimingTodayResponse);
|
rpc SchedTimingToday(generic.Empty) returns (SchedTimingTodayResponse);
|
||||||
rpc StudiedToday(Empty) returns (String);
|
rpc StudiedToday(generic.Empty) returns (generic.String);
|
||||||
rpc StudiedTodayMessage(StudiedTodayMessageRequest) returns (String);
|
rpc StudiedTodayMessage(StudiedTodayMessageRequest) returns (generic.String);
|
||||||
rpc UpdateStats(UpdateStatsRequest) returns (Empty);
|
rpc UpdateStats(UpdateStatsRequest) returns (generic.Empty);
|
||||||
rpc ExtendLimits(ExtendLimitsRequest) returns (Empty);
|
rpc ExtendLimits(ExtendLimitsRequest) returns (generic.Empty);
|
||||||
rpc CountsForDeckToday(DeckId) returns (CountsForDeckTodayResponse);
|
rpc CountsForDeckToday(DeckId) returns (CountsForDeckTodayResponse);
|
||||||
rpc CongratsInfo(Empty) returns (CongratsInfoResponse);
|
rpc CongratsInfo(generic.Empty) returns (CongratsInfoResponse);
|
||||||
rpc RestoreBuriedAndSuspendedCards(CardIds) returns (OpChanges);
|
rpc RestoreBuriedAndSuspendedCards(CardIds) returns (OpChanges);
|
||||||
rpc UnburyDeck(UnburyDeckRequest) returns (OpChanges);
|
rpc UnburyDeck(UnburyDeckRequest) returns (OpChanges);
|
||||||
rpc BuryOrSuspendCards(BuryOrSuspendCardsRequest)
|
rpc BuryOrSuspendCards(BuryOrSuspendCardsRequest)
|
||||||
|
@ -133,35 +85,35 @@ service SchedulingService {
|
||||||
rpc SortCards(SortCardsRequest) returns (OpChangesWithCount);
|
rpc SortCards(SortCardsRequest) returns (OpChangesWithCount);
|
||||||
rpc SortDeck(SortDeckRequest) returns (OpChangesWithCount);
|
rpc SortDeck(SortDeckRequest) returns (OpChangesWithCount);
|
||||||
rpc GetNextCardStates(CardId) returns (NextCardStates);
|
rpc GetNextCardStates(CardId) returns (NextCardStates);
|
||||||
rpc DescribeNextStates(NextCardStates) returns (StringList);
|
rpc DescribeNextStates(NextCardStates) returns (generic.StringList);
|
||||||
rpc StateIsLeech(SchedulingState) returns (Bool);
|
rpc StateIsLeech(SchedulingState) returns (generic.Bool);
|
||||||
rpc AnswerCard(CardAnswer) returns (OpChanges);
|
rpc AnswerCard(CardAnswer) returns (OpChanges);
|
||||||
rpc UpgradeScheduler(Empty) returns (Empty);
|
rpc UpgradeScheduler(generic.Empty) returns (generic.Empty);
|
||||||
rpc GetQueuedCards(GetQueuedCardsRequest) returns (QueuedCards);
|
rpc GetQueuedCards(GetQueuedCardsRequest) returns (QueuedCards);
|
||||||
}
|
}
|
||||||
|
|
||||||
service DecksService {
|
service DecksService {
|
||||||
rpc AddDeckLegacy(Json) returns (OpChangesWithId);
|
rpc AddDeckLegacy(generic.Json) returns (OpChangesWithId);
|
||||||
rpc AddOrUpdateDeckLegacy(AddOrUpdateDeckLegacyRequest) returns (DeckId);
|
rpc AddOrUpdateDeckLegacy(AddOrUpdateDeckLegacyRequest) returns (DeckId);
|
||||||
rpc DeckTree(DeckTreeRequest) returns (DeckTreeNode);
|
rpc DeckTree(DeckTreeRequest) returns (DeckTreeNode);
|
||||||
rpc DeckTreeLegacy(Empty) returns (Json);
|
rpc DeckTreeLegacy(generic.Empty) returns (generic.Json);
|
||||||
rpc GetAllDecksLegacy(Empty) returns (Json);
|
rpc GetAllDecksLegacy(generic.Empty) returns (generic.Json);
|
||||||
rpc GetDeckIdByName(String) returns (DeckId);
|
rpc GetDeckIdByName(generic.String) returns (DeckId);
|
||||||
rpc GetDeck(DeckId) returns (Deck);
|
rpc GetDeck(DeckId) returns (Deck);
|
||||||
rpc UpdateDeck(Deck) returns (OpChanges);
|
rpc UpdateDeck(Deck) returns (OpChanges);
|
||||||
rpc UpdateDeckLegacy(Json) returns (OpChanges);
|
rpc UpdateDeckLegacy(generic.Json) returns (OpChanges);
|
||||||
rpc SetDeckCollapsed(SetDeckCollapsedRequest) returns (OpChanges);
|
rpc SetDeckCollapsed(SetDeckCollapsedRequest) returns (OpChanges);
|
||||||
rpc GetDeckLegacy(DeckId) returns (Json);
|
rpc GetDeckLegacy(DeckId) returns (generic.Json);
|
||||||
rpc GetDeckNames(GetDeckNamesRequest) returns (DeckNames);
|
rpc GetDeckNames(GetDeckNamesRequest) returns (DeckNames);
|
||||||
rpc NewDeckLegacy(Bool) returns (Json);
|
rpc NewDeckLegacy(generic.Bool) returns (generic.Json);
|
||||||
rpc RemoveDecks(DeckIds) returns (OpChangesWithCount);
|
rpc RemoveDecks(DeckIds) returns (OpChangesWithCount);
|
||||||
rpc ReparentDecks(ReparentDecksRequest) returns (OpChangesWithCount);
|
rpc ReparentDecks(ReparentDecksRequest) returns (OpChangesWithCount);
|
||||||
rpc RenameDeck(RenameDeckRequest) returns (OpChanges);
|
rpc RenameDeck(RenameDeckRequest) returns (OpChanges);
|
||||||
rpc GetOrCreateFilteredDeck(DeckId) returns (FilteredDeckForUpdate);
|
rpc GetOrCreateFilteredDeck(DeckId) returns (FilteredDeckForUpdate);
|
||||||
rpc AddOrUpdateFilteredDeck(FilteredDeckForUpdate) returns (OpChangesWithId);
|
rpc AddOrUpdateFilteredDeck(FilteredDeckForUpdate) returns (OpChangesWithId);
|
||||||
rpc FilteredDeckOrderLabels(Empty) returns (StringList);
|
rpc FilteredDeckOrderLabels(generic.Empty) returns (generic.StringList);
|
||||||
rpc SetCurrentDeck(DeckId) returns (OpChanges);
|
rpc SetCurrentDeck(DeckId) returns (OpChanges);
|
||||||
rpc GetCurrentDeck(Empty) returns (Deck);
|
rpc GetCurrentDeck(generic.Empty) returns (Deck);
|
||||||
}
|
}
|
||||||
|
|
||||||
service NotesService {
|
service NotesService {
|
||||||
|
@ -181,47 +133,48 @@ service NotesService {
|
||||||
}
|
}
|
||||||
|
|
||||||
service SyncService {
|
service SyncService {
|
||||||
rpc SyncMedia(SyncAuth) returns (Empty);
|
rpc SyncMedia(SyncAuth) returns (generic.Empty);
|
||||||
rpc AbortSync(Empty) returns (Empty);
|
rpc AbortSync(generic.Empty) returns (generic.Empty);
|
||||||
rpc AbortMediaSync(Empty) returns (Empty);
|
rpc AbortMediaSync(generic.Empty) returns (generic.Empty);
|
||||||
rpc BeforeUpload(Empty) returns (Empty);
|
rpc BeforeUpload(generic.Empty) returns (generic.Empty);
|
||||||
rpc SyncLogin(SyncLoginRequest) returns (SyncAuth);
|
rpc SyncLogin(SyncLoginRequest) returns (SyncAuth);
|
||||||
rpc SyncStatus(SyncAuth) returns (SyncStatusResponse);
|
rpc SyncStatus(SyncAuth) returns (SyncStatusResponse);
|
||||||
rpc SyncCollection(SyncAuth) returns (SyncCollectionResponse);
|
rpc SyncCollection(SyncAuth) returns (SyncCollectionResponse);
|
||||||
rpc FullUpload(SyncAuth) returns (Empty);
|
rpc FullUpload(SyncAuth) returns (generic.Empty);
|
||||||
rpc FullDownload(SyncAuth) returns (Empty);
|
rpc FullDownload(SyncAuth) returns (generic.Empty);
|
||||||
rpc SyncServerMethod(SyncServerMethodRequest) returns (Json);
|
rpc SyncServerMethod(SyncServerMethodRequest) returns (generic.Json);
|
||||||
}
|
}
|
||||||
|
|
||||||
service ConfigService {
|
service ConfigService {
|
||||||
rpc GetConfigJson(String) returns (Json);
|
rpc GetConfigJson(generic.String) returns (generic.Json);
|
||||||
rpc SetConfigJson(SetConfigJsonRequest) returns (OpChanges);
|
rpc SetConfigJson(SetConfigJsonRequest) returns (OpChanges);
|
||||||
rpc SetConfigJsonNoUndo(SetConfigJsonRequest) returns (Empty);
|
rpc SetConfigJsonNoUndo(SetConfigJsonRequest) returns (generic.Empty);
|
||||||
rpc RemoveConfig(String) returns (OpChanges);
|
rpc RemoveConfig(generic.String) returns (OpChanges);
|
||||||
rpc GetAllConfig(Empty) returns (Json);
|
rpc GetAllConfig(generic.Empty) returns (generic.Json);
|
||||||
rpc GetConfigBool(Config.Bool) returns (Bool);
|
rpc GetConfigBool(Config.Bool) returns (generic.Bool);
|
||||||
rpc SetConfigBool(SetConfigBoolRequest) returns (OpChanges);
|
rpc SetConfigBool(SetConfigBoolRequest) returns (OpChanges);
|
||||||
rpc GetConfigString(Config.String) returns (String);
|
rpc GetConfigString(Config.String) returns (generic.String);
|
||||||
rpc SetConfigString(SetConfigStringRequest) returns (OpChanges);
|
rpc SetConfigString(SetConfigStringRequest) returns (OpChanges);
|
||||||
rpc GetPreferences(Empty) returns (Preferences);
|
rpc GetPreferences(generic.Empty) returns (Preferences);
|
||||||
rpc SetPreferences(Preferences) returns (OpChanges);
|
rpc SetPreferences(Preferences) returns (OpChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
service NotetypesService {
|
service NotetypesService {
|
||||||
rpc AddNotetype(Notetype) returns (OpChangesWithId);
|
rpc AddNotetype(Notetype) returns (OpChangesWithId);
|
||||||
rpc UpdateNotetype(Notetype) returns (OpChanges);
|
rpc UpdateNotetype(Notetype) returns (OpChanges);
|
||||||
rpc AddNotetypeLegacy(Json) returns (OpChangesWithId);
|
rpc AddNotetypeLegacy(generic.Json) returns (OpChangesWithId);
|
||||||
rpc UpdateNotetypeLegacy(Json) returns (OpChanges);
|
rpc UpdateNotetypeLegacy(generic.Json) returns (OpChanges);
|
||||||
rpc AddOrUpdateNotetype(AddOrUpdateNotetypeRequest) returns (NotetypeId);
|
rpc AddOrUpdateNotetype(AddOrUpdateNotetypeRequest) returns (NotetypeId);
|
||||||
rpc GetStockNotetypeLegacy(StockNotetype) returns (Json);
|
rpc GetStockNotetypeLegacy(StockNotetype) returns (generic.Json);
|
||||||
rpc GetNotetype(NotetypeId) returns (Notetype);
|
rpc GetNotetype(NotetypeId) returns (Notetype);
|
||||||
rpc GetNotetypeLegacy(NotetypeId) returns (Json);
|
rpc GetNotetypeLegacy(NotetypeId) returns (generic.Json);
|
||||||
rpc GetNotetypeNames(Empty) returns (NotetypeNames);
|
rpc GetNotetypeNames(generic.Empty) returns (NotetypeNames);
|
||||||
rpc GetNotetypeNamesAndCounts(Empty) returns (NotetypeUseCounts);
|
rpc GetNotetypeNamesAndCounts(generic.Empty) returns (NotetypeUseCounts);
|
||||||
rpc GetNotetypeIdByName(String) returns (NotetypeId);
|
rpc GetNotetypeIdByName(generic.String) returns (NotetypeId);
|
||||||
rpc RemoveNotetype(NotetypeId) returns (OpChanges);
|
rpc RemoveNotetype(NotetypeId) returns (OpChanges);
|
||||||
rpc GetAuxNotetypeConfigKey(GetAuxConfigKeyRequest) returns (String);
|
rpc GetAuxNotetypeConfigKey(GetAuxConfigKeyRequest) returns (generic.String);
|
||||||
rpc GetAuxTemplateConfigKey(GetAuxTemplateConfigKeyRequest) returns (String);
|
rpc GetAuxTemplateConfigKey(GetAuxTemplateConfigKeyRequest)
|
||||||
|
returns (generic.String);
|
||||||
rpc GetSingleNotetypeOfNotes(NoteIds) returns (NotetypeId);
|
rpc GetSingleNotetypeOfNotes(NoteIds) returns (NotetypeId);
|
||||||
rpc GetChangeNotetypeInfo(GetChangeNotetypeInfoRequest)
|
rpc GetChangeNotetypeInfo(GetChangeNotetypeInfoRequest)
|
||||||
returns (ChangeNotetypeInfo);
|
returns (ChangeNotetypeInfo);
|
||||||
|
@ -231,34 +184,34 @@ service NotetypesService {
|
||||||
service CardRenderingService {
|
service CardRenderingService {
|
||||||
rpc ExtractAVTags(ExtractAVTagsRequest) returns (ExtractAVTagsResponse);
|
rpc ExtractAVTags(ExtractAVTagsRequest) returns (ExtractAVTagsResponse);
|
||||||
rpc ExtractLatex(ExtractLatexRequest) returns (ExtractLatexResponse);
|
rpc ExtractLatex(ExtractLatexRequest) returns (ExtractLatexResponse);
|
||||||
rpc GetEmptyCards(Empty) returns (EmptyCardsReport);
|
rpc GetEmptyCards(generic.Empty) returns (EmptyCardsReport);
|
||||||
rpc RenderExistingCard(RenderExistingCardRequest)
|
rpc RenderExistingCard(RenderExistingCardRequest)
|
||||||
returns (RenderCardResponse);
|
returns (RenderCardResponse);
|
||||||
rpc RenderUncommittedCard(RenderUncommittedCardRequest)
|
rpc RenderUncommittedCard(RenderUncommittedCardRequest)
|
||||||
returns (RenderCardResponse);
|
returns (RenderCardResponse);
|
||||||
rpc RenderUncommittedCardLegacy(RenderUncommittedCardLegacyRequest)
|
rpc RenderUncommittedCardLegacy(RenderUncommittedCardLegacyRequest)
|
||||||
returns (RenderCardResponse);
|
returns (RenderCardResponse);
|
||||||
rpc StripAVTags(String) returns (String);
|
rpc StripAVTags(generic.String) returns (generic.String);
|
||||||
rpc RenderMarkdown(RenderMarkdownRequest) returns (String);
|
rpc RenderMarkdown(RenderMarkdownRequest) returns (generic.String);
|
||||||
}
|
}
|
||||||
|
|
||||||
service DeckConfigService {
|
service DeckConfigService {
|
||||||
rpc AddOrUpdateDeckConfigLegacy(Json) returns (DeckConfigId);
|
rpc AddOrUpdateDeckConfigLegacy(generic.Json) returns (DeckConfigId);
|
||||||
rpc GetDeckConfig(DeckConfigId) returns (DeckConfig);
|
rpc GetDeckConfig(DeckConfigId) returns (DeckConfig);
|
||||||
rpc AllDeckConfigLegacy(Empty) returns (Json);
|
rpc AllDeckConfigLegacy(generic.Empty) returns (generic.Json);
|
||||||
rpc GetDeckConfigLegacy(DeckConfigId) returns (Json);
|
rpc GetDeckConfigLegacy(DeckConfigId) returns (generic.Json);
|
||||||
rpc NewDeckConfigLegacy(Empty) returns (Json);
|
rpc NewDeckConfigLegacy(generic.Empty) returns (generic.Json);
|
||||||
rpc RemoveDeckConfig(DeckConfigId) returns (Empty);
|
rpc RemoveDeckConfig(DeckConfigId) returns (generic.Empty);
|
||||||
rpc GetDeckConfigsForUpdate(DeckId) returns (DeckConfigsForUpdate);
|
rpc GetDeckConfigsForUpdate(DeckId) returns (DeckConfigsForUpdate);
|
||||||
rpc UpdateDeckConfigs(UpdateDeckConfigsRequest) returns (OpChanges);
|
rpc UpdateDeckConfigs(UpdateDeckConfigsRequest) returns (OpChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
service TagsService {
|
service TagsService {
|
||||||
rpc ClearUnusedTags(Empty) returns (OpChangesWithCount);
|
rpc ClearUnusedTags(generic.Empty) returns (OpChangesWithCount);
|
||||||
rpc AllTags(Empty) returns (StringList);
|
rpc AllTags(generic.Empty) returns (generic.StringList);
|
||||||
rpc RemoveTags(String) returns (OpChangesWithCount);
|
rpc RemoveTags(generic.String) returns (OpChangesWithCount);
|
||||||
rpc SetTagCollapsed(SetTagCollapsedRequest) returns (OpChanges);
|
rpc SetTagCollapsed(SetTagCollapsedRequest) returns (OpChanges);
|
||||||
rpc TagTree(Empty) returns (TagTreeNode);
|
rpc TagTree(generic.Empty) returns (TagTreeNode);
|
||||||
rpc ReparentTags(ReparentTagsRequest) returns (OpChangesWithCount);
|
rpc ReparentTags(ReparentTagsRequest) returns (OpChangesWithCount);
|
||||||
rpc RenameTags(RenameTagsRequest) returns (OpChangesWithCount);
|
rpc RenameTags(RenameTagsRequest) returns (OpChangesWithCount);
|
||||||
rpc AddNoteTags(NoteIdsAndTagsRequest) returns (OpChangesWithCount);
|
rpc AddNoteTags(NoteIdsAndTagsRequest) returns (OpChangesWithCount);
|
||||||
|
@ -267,55 +220,49 @@ service TagsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
service SearchService {
|
service SearchService {
|
||||||
rpc BuildSearchString(SearchNode) returns (String);
|
rpc BuildSearchString(SearchNode) returns (generic.String);
|
||||||
rpc SearchCards(SearchRequest) returns (SearchResponse);
|
rpc SearchCards(SearchRequest) returns (SearchResponse);
|
||||||
rpc SearchNotes(SearchRequest) returns (SearchResponse);
|
rpc SearchNotes(SearchRequest) returns (SearchResponse);
|
||||||
rpc JoinSearchNodes(JoinSearchNodesRequest) returns (String);
|
rpc JoinSearchNodes(JoinSearchNodesRequest) returns (generic.String);
|
||||||
rpc ReplaceSearchNode(ReplaceSearchNodeRequest) returns (String);
|
rpc ReplaceSearchNode(ReplaceSearchNodeRequest) returns (generic.String);
|
||||||
rpc FindAndReplace(FindAndReplaceRequest) returns (OpChangesWithCount);
|
rpc FindAndReplace(FindAndReplaceRequest) returns (OpChangesWithCount);
|
||||||
rpc AllBrowserColumns(Empty) returns (BrowserColumns);
|
rpc AllBrowserColumns(generic.Empty) returns (BrowserColumns);
|
||||||
rpc BrowserRowForId(Int64) returns (BrowserRow);
|
rpc BrowserRowForId(generic.Int64) returns (BrowserRow);
|
||||||
rpc SetActiveBrowserColumns(StringList) returns (Empty);
|
rpc SetActiveBrowserColumns(generic.StringList) returns (generic.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
service StatsService {
|
service StatsService {
|
||||||
rpc CardStats(CardId) returns (String);
|
rpc CardStats(CardId) returns (generic.String);
|
||||||
rpc Graphs(GraphsRequest) returns (GraphsResponse);
|
rpc Graphs(GraphsRequest) returns (GraphsResponse);
|
||||||
rpc GetGraphPreferences(Empty) returns (GraphPreferences);
|
rpc GetGraphPreferences(generic.Empty) returns (GraphPreferences);
|
||||||
rpc SetGraphPreferences(GraphPreferences) returns (Empty);
|
rpc SetGraphPreferences(GraphPreferences) returns (generic.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
service MediaService {
|
service MediaService {
|
||||||
rpc CheckMedia(Empty) returns (CheckMediaResponse);
|
rpc CheckMedia(generic.Empty) returns (CheckMediaResponse);
|
||||||
rpc TrashMediaFiles(TrashMediaFilesRequest) returns (Empty);
|
rpc TrashMediaFiles(TrashMediaFilesRequest) returns (generic.Empty);
|
||||||
rpc AddMediaFile(AddMediaFileRequest) returns (String);
|
rpc AddMediaFile(AddMediaFileRequest) returns (generic.String);
|
||||||
rpc EmptyTrash(Empty) returns (Empty);
|
rpc EmptyTrash(generic.Empty) returns (generic.Empty);
|
||||||
rpc RestoreTrash(Empty) returns (Empty);
|
rpc RestoreTrash(generic.Empty) returns (generic.Empty);
|
||||||
}
|
|
||||||
|
|
||||||
service I18nService {
|
|
||||||
rpc TranslateString(TranslateStringRequest) returns (String);
|
|
||||||
rpc FormatTimespan(FormatTimespanRequest) returns (String);
|
|
||||||
rpc I18nResources(I18nResourcesRequest) returns (Json);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
service CollectionService {
|
service CollectionService {
|
||||||
rpc OpenCollection(OpenCollectionRequest) returns (Empty);
|
rpc OpenCollection(OpenCollectionRequest) returns (generic.Empty);
|
||||||
rpc CloseCollection(CloseCollectionRequest) returns (Empty);
|
rpc CloseCollection(CloseCollectionRequest) returns (generic.Empty);
|
||||||
rpc CheckDatabase(Empty) returns (CheckDatabaseResponse);
|
rpc CheckDatabase(generic.Empty) returns (CheckDatabaseResponse);
|
||||||
rpc GetUndoStatus(Empty) returns (UndoStatus);
|
rpc GetUndoStatus(generic.Empty) returns (UndoStatus);
|
||||||
rpc Undo(Empty) returns (OpChangesAfterUndo);
|
rpc Undo(generic.Empty) returns (OpChangesAfterUndo);
|
||||||
rpc Redo(Empty) returns (OpChangesAfterUndo);
|
rpc Redo(generic.Empty) returns (OpChangesAfterUndo);
|
||||||
rpc AddCustomUndoEntry(String) returns (UInt32);
|
rpc AddCustomUndoEntry(generic.String) returns (generic.UInt32);
|
||||||
rpc MergeUndoEntries(UInt32) returns (OpChanges);
|
rpc MergeUndoEntries(generic.UInt32) returns (OpChanges);
|
||||||
rpc LatestProgress(Empty) returns (Progress);
|
rpc LatestProgress(generic.Empty) returns (Progress);
|
||||||
rpc SetWantsAbort(Empty) returns (Empty);
|
rpc SetWantsAbort(generic.Empty) returns (generic.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
service CardsService {
|
service CardsService {
|
||||||
rpc GetCard(CardId) returns (Card);
|
rpc GetCard(CardId) returns (Card);
|
||||||
rpc UpdateCard(UpdateCardRequest) returns (OpChanges);
|
rpc UpdateCard(UpdateCardRequest) returns (OpChanges);
|
||||||
rpc RemoveCards(RemoveCardsRequest) returns (Empty);
|
rpc RemoveCards(RemoveCardsRequest) returns (generic.Empty);
|
||||||
rpc SetDeck(SetDeckRequest) returns (OpChangesWithCount);
|
rpc SetDeck(SetDeckRequest) returns (OpChangesWithCount);
|
||||||
rpc SetFlag(SetFlagRequest) returns (OpChangesWithCount);
|
rpc SetFlag(SetFlagRequest) returns (OpChangesWithCount);
|
||||||
}
|
}
|
||||||
|
@ -525,7 +472,7 @@ message Notetype {
|
||||||
|
|
||||||
bytes other = 255;
|
bytes other = 255;
|
||||||
}
|
}
|
||||||
OptionalUInt32 ord = 1;
|
generic.OptionalUInt32 ord = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
Config config = 5;
|
Config config = 5;
|
||||||
}
|
}
|
||||||
|
@ -542,7 +489,7 @@ message Notetype {
|
||||||
bytes other = 255;
|
bytes other = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionalUInt32 ord = 1;
|
generic.OptionalUInt32 ord = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
int64 mtime_secs = 3;
|
int64 mtime_secs = 3;
|
||||||
sint32 usn = 4;
|
sint32 usn = 4;
|
||||||
|
@ -661,7 +608,7 @@ message Progress {
|
||||||
uint32 stage_current = 3;
|
uint32 stage_current = 3;
|
||||||
}
|
}
|
||||||
oneof value {
|
oneof value {
|
||||||
Empty none = 1;
|
generic.Empty none = 1;
|
||||||
MediaSync media_sync = 2;
|
MediaSync media_sync = 2;
|
||||||
string media_check = 3;
|
string media_check = 3;
|
||||||
FullSync full_sync = 4;
|
FullSync full_sync = 4;
|
||||||
|
@ -797,34 +744,6 @@ message TrashMediaFilesRequest {
|
||||||
repeated string fnames = 1;
|
repeated string fnames = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TranslateStringRequest {
|
|
||||||
uint32 module_index = 1;
|
|
||||||
uint32 message_index = 2;
|
|
||||||
map<string, TranslateArgValue> args = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message TranslateArgValue {
|
|
||||||
oneof value {
|
|
||||||
string str = 1;
|
|
||||||
double number = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message FormatTimespanRequest {
|
|
||||||
enum Context {
|
|
||||||
PRECISE = 0;
|
|
||||||
ANSWER_BUTTONS = 1;
|
|
||||||
INTERVALS = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
float seconds = 1;
|
|
||||||
Context context = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message I18nResourcesRequest {
|
|
||||||
repeated string modules = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message StudiedTodayMessageRequest {
|
message StudiedTodayMessageRequest {
|
||||||
uint32 cards = 1;
|
uint32 cards = 1;
|
||||||
double seconds = 2;
|
double seconds = 2;
|
||||||
|
@ -857,7 +776,7 @@ message SortOrder {
|
||||||
bool reverse = 2;
|
bool reverse = 2;
|
||||||
}
|
}
|
||||||
oneof value {
|
oneof value {
|
||||||
Empty none = 1;
|
generic.Empty none = 1;
|
||||||
string custom = 2;
|
string custom = 2;
|
||||||
Builtin builtin = 3;
|
Builtin builtin = 3;
|
||||||
}
|
}
|
||||||
|
@ -1606,6 +1525,16 @@ message OpChanges {
|
||||||
bool study_queues = 10;
|
bool study_queues = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message OpChangesWithCount {
|
||||||
|
uint32 count = 1;
|
||||||
|
OpChanges changes = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OpChangesWithId {
|
||||||
|
int64 id = 1;
|
||||||
|
OpChanges changes = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message UndoStatus {
|
message UndoStatus {
|
||||||
string undo = 1;
|
string undo = 1;
|
||||||
string redo = 2;
|
string redo = 2;
|
44
proto/anki/generic.proto
Normal file
44
proto/anki/generic.proto
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package anki.generic;
|
||||||
|
|
||||||
|
message Empty {}
|
||||||
|
|
||||||
|
message OptionalInt32 {
|
||||||
|
sint32 val = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OptionalUInt32 {
|
||||||
|
uint32 val = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Int32 {
|
||||||
|
sint32 val = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UInt32 {
|
||||||
|
uint32 val = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Int64 {
|
||||||
|
int64 val = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message String {
|
||||||
|
string val = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Json {
|
||||||
|
bytes json = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Bool {
|
||||||
|
bool val = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StringList {
|
||||||
|
repeated string vals = 1;
|
||||||
|
}
|
42
proto/anki/i18n.proto
Normal file
42
proto/anki/i18n.proto
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package anki.i18n;
|
||||||
|
|
||||||
|
import "anki/generic.proto";
|
||||||
|
|
||||||
|
service I18nService {
|
||||||
|
rpc TranslateString(TranslateStringRequest) returns (generic.String);
|
||||||
|
rpc FormatTimespan(FormatTimespanRequest) returns (generic.String);
|
||||||
|
rpc I18nResources(I18nResourcesRequest) returns (generic.Json);
|
||||||
|
}
|
||||||
|
|
||||||
|
message TranslateStringRequest {
|
||||||
|
uint32 module_index = 1;
|
||||||
|
uint32 message_index = 2;
|
||||||
|
map<string, TranslateArgValue> args = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TranslateArgValue {
|
||||||
|
oneof value {
|
||||||
|
string str = 1;
|
||||||
|
double number = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message FormatTimespanRequest {
|
||||||
|
enum Context {
|
||||||
|
PRECISE = 0;
|
||||||
|
ANSWER_BUTTONS = 1;
|
||||||
|
INTERVALS = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
float seconds = 1;
|
||||||
|
Context context = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message I18nResourcesRequest {
|
||||||
|
repeated string modules = 1;
|
||||||
|
}
|
|
@ -14,9 +14,9 @@ def _impl(rctx):
|
||||||
alias(
|
alias(
|
||||||
name = "clang_format",
|
name = "clang_format",
|
||||||
actual = select({
|
actual = select({
|
||||||
"@net_ankiweb_anki//platforms:windows_x86_64": "@clang_format_windows_x86_64//:clang-format.exe",
|
"@anki//platforms:windows_x86_64": "@clang_format_windows_x86_64//:clang-format.exe",
|
||||||
"@net_ankiweb_anki//platforms:macos_x86_64": "@clang_format_macos_x86_64//:clang-format",
|
"@anki//platforms:macos_x86_64": "@clang_format_macos_x86_64//:clang-format",
|
||||||
"@net_ankiweb_anki//platforms:linux_x86_64": "@clang_format_linux_x86_64//:clang-format",
|
"@anki//platforms:linux_x86_64": "@clang_format_linux_x86_64//:clang-format",
|
||||||
}),
|
}),
|
||||||
visibility = ["//visibility:public"]
|
visibility = ["//visibility:public"]
|
||||||
)
|
)
|
||||||
|
@ -68,7 +68,7 @@ def proto_format(name, srcs, **kwargs):
|
||||||
py_test(
|
py_test(
|
||||||
name = name,
|
name = name,
|
||||||
srcs = [
|
srcs = [
|
||||||
"format.py",
|
"@anki//proto:format.py",
|
||||||
],
|
],
|
||||||
data = ["@clang_format//:clang_format"] + srcs,
|
data = ["@clang_format//:clang_format"] + srcs,
|
||||||
args = ["$(location @clang_format//:clang_format)"] + [native.package_name() + "/" + f for f in srcs],
|
args = ["$(location @clang_format//:clang_format)"] + [native.package_name() + "/" + f for f in srcs],
|
||||||
|
|
|
@ -14,9 +14,9 @@ def _impl(rctx):
|
||||||
alias(
|
alias(
|
||||||
name = "clang_format",
|
name = "clang_format",
|
||||||
actual = select({
|
actual = select({
|
||||||
"@net_ankiweb_anki//platforms:windows_x86_64": "@clang_format_windows_x86_64//:clang-format.exe",
|
"@anki//platforms:windows_x86_64": "@clang_format_windows_x86_64//:clang-format.exe",
|
||||||
"@net_ankiweb_anki//platforms:macos_x86_64": "@clang_format_macos_x86_64//:clang-format",
|
"@anki//platforms:macos_x86_64": "@clang_format_macos_x86_64//:clang-format",
|
||||||
"@net_ankiweb_anki//platforms:linux_x86_64": "@clang_format_linux_x86_64//:clang-format",
|
"@anki//platforms:linux_x86_64": "@clang_format_linux_x86_64//:clang-format",
|
||||||
}),
|
}),
|
||||||
visibility = ["//visibility:public"]
|
visibility = ["//visibility:public"]
|
||||||
)
|
)
|
||||||
|
@ -68,7 +68,7 @@ def proto_format(name, srcs, **kwargs):
|
||||||
py_test(
|
py_test(
|
||||||
name = name,
|
name = name,
|
||||||
srcs = [
|
srcs = [
|
||||||
"format.py",
|
"@anki//format.py",
|
||||||
],
|
],
|
||||||
data = ["@clang_format//:clang_format"] + srcs,
|
data = ["@clang_format//:clang_format"] + srcs,
|
||||||
args = ["$(location @clang_format//:clang_format)"] + [native.package_name() + "/" + f for f in srcs],
|
args = ["$(location @clang_format//:clang_format)"] + [native.package_name() + "/" + f for f in srcs],
|
||||||
|
|
|
@ -12,10 +12,10 @@ def _impl(rctx):
|
||||||
alias(
|
alias(
|
||||||
name = "protoc",
|
name = "protoc",
|
||||||
actual = select({
|
actual = select({
|
||||||
"@net_ankiweb_anki//platforms:windows_x86_64": "@protoc_bin_windows//:bin/protoc.exe",
|
"@anki//platforms:windows_x86_64": "@protoc_bin_windows//:bin/protoc.exe",
|
||||||
"@net_ankiweb_anki//platforms:macos_x86_64": "@protoc_bin_macos//:bin/protoc",
|
"@anki//platforms:macos_x86_64": "@protoc_bin_macos//:bin/protoc",
|
||||||
"@net_ankiweb_anki//platforms:linux_x86_64": "@protoc_bin_linux_x86_64//:bin/protoc",
|
"@anki//platforms:linux_x86_64": "@protoc_bin_linux_x86_64//:bin/protoc",
|
||||||
"@net_ankiweb_anki//platforms:linux_arm64": "@protoc_bin_linux_arm64//:bin/protoc"
|
"@anki//platforms:linux_arm64": "@protoc_bin_linux_arm64//:bin/protoc"
|
||||||
}),
|
}),
|
||||||
visibility = ["//visibility:public"]
|
visibility = ["//visibility:public"]
|
||||||
)
|
)
|
||||||
|
|
|
@ -32,6 +32,7 @@ py_library(
|
||||||
"py.typed",
|
"py.typed",
|
||||||
":buildinfo",
|
":buildinfo",
|
||||||
":hooks_gen",
|
":hooks_gen",
|
||||||
|
":proto",
|
||||||
"//pylib/anki/_backend",
|
"//pylib/anki/_backend",
|
||||||
],
|
],
|
||||||
imports = [
|
imports = [
|
||||||
|
@ -105,3 +106,30 @@ filegroup(
|
||||||
"//pylib:__subpackages__",
|
"//pylib:__subpackages__",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
load("//pylib:protobuf.bzl", "py_proto")
|
||||||
|
|
||||||
|
py_proto(
|
||||||
|
name = "proto_files",
|
||||||
|
srcs = ["//proto"],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "proto",
|
||||||
|
srcs = [
|
||||||
|
# "__init__.py",
|
||||||
|
":proto_files",
|
||||||
|
],
|
||||||
|
visibility = ["//pylib:__subpackages__"],
|
||||||
|
)
|
||||||
|
|
||||||
|
# only used for genbackend.py
|
||||||
|
py_library(
|
||||||
|
name = "proto_lib",
|
||||||
|
srcs = [":proto"],
|
||||||
|
imports = [".."],
|
||||||
|
visibility = ["//pylib:__subpackages__"],
|
||||||
|
)
|
||||||
|
|
|
@ -1,27 +1,18 @@
|
||||||
load("@rules_python//python:defs.bzl", "py_binary")
|
load("@rules_python//python:defs.bzl", "py_binary")
|
||||||
load("@py_deps//:requirements.bzl", "requirement")
|
load("@py_deps//:requirements.bzl", "requirement")
|
||||||
load("//pylib:protobuf.bzl", "py_proto_library_typed")
|
|
||||||
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
|
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
|
||||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||||
|
|
||||||
py_proto_library_typed(
|
|
||||||
name = "backend_pb2",
|
|
||||||
src = "//proto:backend.proto",
|
|
||||||
visibility = [
|
|
||||||
"//visibility:public",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
py_binary(
|
py_binary(
|
||||||
name = "genbackend",
|
name = "genbackend",
|
||||||
srcs = [
|
srcs = [
|
||||||
"backend_pb2",
|
|
||||||
"genbackend.py",
|
"genbackend.py",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
requirement("black"),
|
requirement("black"),
|
||||||
requirement("stringcase"),
|
requirement("stringcase"),
|
||||||
requirement("protobuf"),
|
requirement("protobuf"),
|
||||||
|
"//pylib/anki:proto_lib",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -94,7 +85,6 @@ filegroup(
|
||||||
srcs = [
|
srcs = [
|
||||||
"__init__.py",
|
"__init__.py",
|
||||||
"rsbridge.pyi",
|
"rsbridge.pyi",
|
||||||
":backend_pb2",
|
|
||||||
":fluent_gen",
|
":fluent_gen",
|
||||||
":rsbackend_gen",
|
":rsbackend_gen",
|
||||||
":rsbridge",
|
":rsbridge",
|
||||||
|
|
|
@ -11,6 +11,7 @@ from weakref import ref
|
||||||
from markdown import markdown
|
from markdown import markdown
|
||||||
|
|
||||||
import anki.buildinfo
|
import anki.buildinfo
|
||||||
|
from anki import backend_pb2, i18n_pb2
|
||||||
from anki._backend.generated import RustBackendGenerated
|
from anki._backend.generated import RustBackendGenerated
|
||||||
from anki.dbproxy import Row as DBRow
|
from anki.dbproxy import Row as DBRow
|
||||||
from anki.dbproxy import ValueForDB
|
from anki.dbproxy import ValueForDB
|
||||||
|
@ -32,7 +33,6 @@ from ..errors import (
|
||||||
TemplateError,
|
TemplateError,
|
||||||
UndoEmpty,
|
UndoEmpty,
|
||||||
)
|
)
|
||||||
from . import backend_pb2 as pb
|
|
||||||
from . import rsbridge
|
from . import rsbridge
|
||||||
from .fluent import GeneratedTranslations, LegacyTranslationEnum
|
from .fluent import GeneratedTranslations, LegacyTranslationEnum
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ class RustBackend(RustBackendGenerated):
|
||||||
if langs is None:
|
if langs is None:
|
||||||
langs = [anki.lang.currentLang]
|
langs = [anki.lang.currentLang]
|
||||||
|
|
||||||
init_msg = pb.BackendInit(
|
init_msg = backend_pb2.BackendInit(
|
||||||
preferred_langs=langs,
|
preferred_langs=langs,
|
||||||
server=server,
|
server=server,
|
||||||
)
|
)
|
||||||
|
@ -95,7 +95,7 @@ class RustBackend(RustBackendGenerated):
|
||||||
return from_json_bytes(self._backend.db_command(to_json_bytes(input)))
|
return from_json_bytes(self._backend.db_command(to_json_bytes(input)))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
err_bytes = bytes(e.args[0])
|
err_bytes = bytes(e.args[0])
|
||||||
err = pb.BackendError()
|
err = backend_pb2.BackendError()
|
||||||
err.ParseFromString(err_bytes)
|
err.ParseFromString(err_bytes)
|
||||||
raise backend_exception_to_pylib(err)
|
raise backend_exception_to_pylib(err)
|
||||||
|
|
||||||
|
@ -125,21 +125,21 @@ class RustBackend(RustBackendGenerated):
|
||||||
return self._backend.command(service, method, input_bytes)
|
return self._backend.command(service, method, input_bytes)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
err_bytes = bytes(e.args[0])
|
err_bytes = bytes(e.args[0])
|
||||||
err = pb.BackendError()
|
err = backend_pb2.BackendError()
|
||||||
err.ParseFromString(err_bytes)
|
err.ParseFromString(err_bytes)
|
||||||
raise backend_exception_to_pylib(err)
|
raise backend_exception_to_pylib(err)
|
||||||
|
|
||||||
|
|
||||||
def translate_string_in(
|
def translate_string_in(
|
||||||
module_index: int, message_index: int, **kwargs: Union[str, int, float]
|
module_index: int, message_index: int, **kwargs: Union[str, int, float]
|
||||||
) -> pb.TranslateStringRequest:
|
) -> i18n_pb2.TranslateStringRequest:
|
||||||
args = {}
|
args = {}
|
||||||
for (k, v) in kwargs.items():
|
for (k, v) in kwargs.items():
|
||||||
if isinstance(v, str):
|
if isinstance(v, str):
|
||||||
args[k] = pb.TranslateArgValue(str=v)
|
args[k] = i18n_pb2.TranslateArgValue(str=v)
|
||||||
else:
|
else:
|
||||||
args[k] = pb.TranslateArgValue(number=v)
|
args[k] = i18n_pb2.TranslateArgValue(number=v)
|
||||||
return pb.TranslateStringRequest(
|
return i18n_pb2.TranslateStringRequest(
|
||||||
module_index=module_index, message_index=message_index, args=args
|
module_index=module_index, message_index=message_index, args=args
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -167,8 +167,8 @@ class Translations(GeneratedTranslations):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def backend_exception_to_pylib(err: pb.BackendError) -> Exception:
|
def backend_exception_to_pylib(err: backend_pb2.BackendError) -> Exception:
|
||||||
kind = pb.BackendError
|
kind = backend_pb2.BackendError
|
||||||
val = err.kind
|
val = err.kind
|
||||||
if val == kind.INTERRUPTED:
|
if val == kind.INTERRUPTED:
|
||||||
return Interrupted()
|
return Interrupted()
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../../../bazel-bin/pylib/anki/_backend/backend_pb2.pyi
|
|
|
@ -7,7 +7,10 @@ import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import google.protobuf.descriptor
|
import google.protobuf.descriptor
|
||||||
import pylib.anki._backend.backend_pb2 as pb
|
|
||||||
|
import anki.backend_pb2
|
||||||
|
import anki.i18n_pb2
|
||||||
|
|
||||||
import stringcase
|
import stringcase
|
||||||
|
|
||||||
TYPE_DOUBLE = 1
|
TYPE_DOUBLE = 1
|
||||||
|
@ -73,11 +76,11 @@ def python_type_inner(field):
|
||||||
raise Exception(f"unknown type: {type}")
|
raise Exception(f"unknown type: {type}")
|
||||||
|
|
||||||
|
|
||||||
def fullname(fullname):
|
def fullname(fullname: str) -> str:
|
||||||
if "FluentString" in fullname:
|
# eg anki.generic.Empty -> anki.generic_pb2.Empty
|
||||||
return fullname.replace("BackendProto", "anki.fluent_pb2")
|
components = fullname.split(".")
|
||||||
else:
|
components[1] += "_pb2"
|
||||||
return fullname.replace("BackendProto", "pb")
|
return ".".join(components)
|
||||||
|
|
||||||
|
|
||||||
# get_deck_i_d -> get_deck_id etc
|
# get_deck_i_d -> get_deck_id etc
|
||||||
|
@ -131,7 +134,7 @@ def render_method(service_idx, method_idx, method):
|
||||||
return_type = python_type(f)
|
return_type = python_type(f)
|
||||||
else:
|
else:
|
||||||
single_field = ""
|
single_field = ""
|
||||||
return_type = f"pb.{method.output_type.name}"
|
return_type = fullname(method.output_type.full_name)
|
||||||
|
|
||||||
if method.name in SKIP_DECODE:
|
if method.name in SKIP_DECODE:
|
||||||
return_type = "bytes"
|
return_type = "bytes"
|
||||||
|
@ -144,7 +147,7 @@ def render_method(service_idx, method_idx, method):
|
||||||
buf += f"""return self._run_command({service_idx}, {method_idx}, input)
|
buf += f"""return self._run_command({service_idx}, {method_idx}, input)
|
||||||
"""
|
"""
|
||||||
else:
|
else:
|
||||||
buf += f"""output = pb.{method.output_type.name}()
|
buf += f"""output = {fullname(method.output_type.full_name)}()
|
||||||
output.ParseFromString(self._run_command({service_idx}, {method_idx}, input))
|
output.ParseFromString(self._run_command({service_idx}, {method_idx}, input))
|
||||||
return output{single_field}
|
return output{single_field}
|
||||||
"""
|
"""
|
||||||
|
@ -162,12 +165,14 @@ def render_service(
|
||||||
out.append(render_method(service_index, method_index, method))
|
out.append(render_method(service_index, method_index, method))
|
||||||
|
|
||||||
|
|
||||||
for service in pb.ServiceIndex.DESCRIPTOR.values:
|
service_modules = dict(I18N="i18n")
|
||||||
|
|
||||||
|
for service in anki.backend_pb2.ServiceIndex.DESCRIPTOR.values:
|
||||||
# SERVICE_INDEX_TEST -> _TESTSERVICE
|
# SERVICE_INDEX_TEST -> _TESTSERVICE
|
||||||
service_var = (
|
base = service.name.replace("SERVICE_INDEX_", "")
|
||||||
"_" + service.name.replace("SERVICE_INDEX", "").replace("_", "") + "SERVICE"
|
service_pkg = (service_modules.get(base) or "backend") + ""
|
||||||
)
|
service_var = "_" + base.replace("_", "") + "SERVICE"
|
||||||
service_obj = getattr(pb, service_var)
|
service_obj = getattr(getattr(anki, service_pkg + "_pb2"), service_var)
|
||||||
service_index = service.number
|
service_index = service.number
|
||||||
render_service(service_obj, service_index)
|
render_service(service_obj, service_index)
|
||||||
|
|
||||||
|
@ -194,7 +199,7 @@ col.decks.all_config()
|
||||||
|
|
||||||
from typing import *
|
from typing import *
|
||||||
|
|
||||||
import anki._backend.backend_pb2 as pb
|
import anki
|
||||||
|
|
||||||
class RustBackendGenerated:
|
class RustBackendGenerated:
|
||||||
def _run_command(self, service: int, method: int, input: Any) -> bytes:
|
def _run_command(self, service: int, method: int, input: Any) -> bytes:
|
||||||
|
|
1
pylib/anki/backend_pb2.pyi
Symbolic link
1
pylib/anki/backend_pb2.pyi
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bazel-bin/pylib/anki/backend_pb2.pyi
|
|
@ -10,7 +10,7 @@ import time
|
||||||
from typing import List, NewType, Optional
|
from typing import List, NewType, Optional
|
||||||
|
|
||||||
import anki # pylint: disable=unused-import
|
import anki # pylint: disable=unused-import
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki._legacy import DeprecatedNamesMixin, deprecated
|
from anki._legacy import DeprecatedNamesMixin, deprecated
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
|
|
|
@ -7,7 +7,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any, Generator, List, Literal, Optional, Sequence, Tuple, Union, cast
|
from typing import Any, Generator, List, Literal, Optional, Sequence, Tuple, Union, cast
|
||||||
|
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
|
|
||||||
# protobuf we publicly export - listed first to avoid circular imports
|
# protobuf we publicly export - listed first to avoid circular imports
|
||||||
from anki._legacy import DeprecatedNamesMixin, deprecated
|
from anki._legacy import DeprecatedNamesMixin, deprecated
|
||||||
|
@ -35,7 +35,7 @@ import weakref
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
import anki.latex
|
import anki.latex
|
||||||
from anki import hooks
|
from anki import generic_pb2, hooks
|
||||||
from anki._backend import RustBackend, Translations
|
from anki._backend import RustBackend, Translations
|
||||||
from anki.browser import BrowserConfig, BrowserDefaults
|
from anki.browser import BrowserConfig, BrowserDefaults
|
||||||
from anki.cards import Card, CardId
|
from anki.cards import Card, CardId
|
||||||
|
@ -492,7 +492,7 @@ class Collection(DeprecatedNamesMixin):
|
||||||
return _pb.SortOrder(custom=order)
|
return _pb.SortOrder(custom=order)
|
||||||
if isinstance(order, bool):
|
if isinstance(order, bool):
|
||||||
if order is False:
|
if order is False:
|
||||||
return _pb.SortOrder(none=_pb.Empty())
|
return _pb.SortOrder(none=generic_pb2.Empty())
|
||||||
# order=True: set args to sort column and reverse from config
|
# order=True: set args to sort column and reverse from config
|
||||||
sort_key = BrowserConfig.sort_column_key(finding_notes)
|
sort_key = BrowserConfig.sort_column_key(finding_notes)
|
||||||
order = self.get_browser_column(self.get_config(sort_key))
|
order = self.get_browser_column(self.get_config(sort_key))
|
||||||
|
@ -506,7 +506,7 @@ class Collection(DeprecatedNamesMixin):
|
||||||
|
|
||||||
# eg, user is ordering on an add-on field with the add-on not installed
|
# eg, user is ordering on an add-on field with the add-on not installed
|
||||||
print(f"{order} is not a valid sort order.")
|
print(f"{order} is not a valid sort order.")
|
||||||
return _pb.SortOrder(none=_pb.Empty())
|
return _pb.SortOrder(none=generic_pb2.Empty())
|
||||||
|
|
||||||
def find_and_replace(
|
def find_and_replace(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -25,7 +25,7 @@ from typing import Any
|
||||||
from weakref import ref
|
from weakref import ref
|
||||||
|
|
||||||
import anki
|
import anki
|
||||||
from anki._backend import backend_pb2 as _pb
|
from anki import backend_pb2 as _pb
|
||||||
from anki.collection import OpChanges
|
from anki.collection import OpChanges
|
||||||
from anki.errors import NotFoundError
|
from anki.errors import NotFoundError
|
||||||
from anki.utils import from_json_bytes, to_json_bytes
|
from anki.utils import from_json_bytes, to_json_bytes
|
||||||
|
|
|
@ -23,7 +23,7 @@ from typing import (
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import anki
|
import anki
|
||||||
|
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
from anki._legacy import DeprecatedNamesMixin, deprecated, print_deprecation_warning
|
from anki._legacy import DeprecatedNamesMixin, deprecated, print_deprecation_warning
|
||||||
from anki.cards import CardId
|
from anki.cards import CardId
|
||||||
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId
|
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId
|
||||||
|
|
1
pylib/anki/generic_pb2.pyi
Symbolic link
1
pylib/anki/generic_pb2.pyi
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bazel-bin/pylib/anki/generic_pb2.pyi
|
1
pylib/anki/i18n_pb2.pyi
Symbolic link
1
pylib/anki/i18n_pb2.pyi
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bazel-bin/pylib/anki/i18n_pb2.pyi
|
|
@ -9,7 +9,8 @@ import weakref
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
import anki
|
import anki
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki._backend
|
||||||
|
import anki.i18n_pb2 as _pb
|
||||||
|
|
||||||
# public exports
|
# public exports
|
||||||
TR = anki._backend.LegacyTranslationEnum
|
TR = anki._backend.LegacyTranslationEnum
|
||||||
|
|
|
@ -10,7 +10,7 @@ from dataclasses import dataclass
|
||||||
from typing import Any, List, Optional, Tuple
|
from typing import Any, List, Optional, Tuple
|
||||||
|
|
||||||
import anki
|
import anki
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.models import NotetypeDict
|
from anki.models import NotetypeDict
|
||||||
from anki.template import TemplateRenderContext, TemplateRenderOutput
|
from anki.template import TemplateRenderContext, TemplateRenderOutput
|
||||||
|
|
|
@ -11,7 +11,7 @@ import time
|
||||||
from typing import Any, Callable, List, Optional, Tuple
|
from typing import Any, Callable, List, Optional, Tuple
|
||||||
|
|
||||||
import anki
|
import anki
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
from anki._legacy import deprecated
|
from anki._legacy import deprecated
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.latex import render_latex, render_latex_returning_errors
|
from anki.latex import render_latex, render_latex_returning_errors
|
||||||
|
|
|
@ -12,7 +12,7 @@ import time
|
||||||
from typing import Any, Dict, List, NewType, Optional, Sequence, Tuple, Union
|
from typing import Any, Dict, List, NewType, Optional, Sequence, Tuple, Union
|
||||||
|
|
||||||
import anki # pylint: disable=unused-import
|
import anki # pylint: disable=unused-import
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
from anki._legacy import DeprecatedNamesMixin, deprecated, print_deprecation_warning
|
from anki._legacy import DeprecatedNamesMixin, deprecated, print_deprecation_warning
|
||||||
from anki.collection import OpChanges, OpChangesWithId
|
from anki.collection import OpChanges, OpChangesWithId
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
|
|
|
@ -9,7 +9,7 @@ import copy
|
||||||
from typing import Any, List, NewType, Optional, Sequence, Tuple, Union
|
from typing import Any, List, NewType, Optional, Sequence, Tuple, Union
|
||||||
|
|
||||||
import anki # pylint: disable=unused-import
|
import anki # pylint: disable=unused-import
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki._legacy import DeprecatedNamesMixin
|
from anki._legacy import DeprecatedNamesMixin
|
||||||
from anki.consts import MODEL_STD
|
from anki.consts import MODEL_STD
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import anki
|
import anki
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId
|
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId
|
||||||
from anki.config import Config
|
from anki.config import Config
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ from heapq import *
|
||||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
import anki # pylint: disable=unused-import
|
import anki # pylint: disable=unused-import
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.cards import Card, CardId
|
from anki.cards import Card, CardId
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
|
|
|
@ -14,7 +14,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import List, Literal, Sequence, Tuple
|
from typing import List, Literal, Sequence, Tuple
|
||||||
|
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
from anki.cards import Card
|
from anki.cards import Card
|
||||||
from anki.collection import OpChanges
|
from anki.collection import OpChanges
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
|
|
|
@ -6,7 +6,7 @@ from __future__ import annotations
|
||||||
from typing import Any, Callable, List, Tuple
|
from typing import Any, Callable, List, Tuple
|
||||||
|
|
||||||
import anki
|
import anki
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
from anki.utils import from_json_bytes
|
from anki.utils import from_json_bytes
|
||||||
|
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Copyright: Ankitects Pty Ltd and contributors
|
# Copyright: Ankitects Pty Ltd and contributors
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
|
|
||||||
# public exports
|
# public exports
|
||||||
SyncAuth = _pb.SyncAuth
|
SyncAuth = _pb.SyncAuth
|
||||||
|
|
|
@ -27,7 +27,7 @@ except ImportError as e:
|
||||||
from flask import Response
|
from flask import Response
|
||||||
|
|
||||||
from anki import Collection
|
from anki import Collection
|
||||||
from anki._backend.backend_pb2 import SyncServerMethodRequest
|
from anki.backend_pb2 import SyncServerMethodRequest
|
||||||
|
|
||||||
Method = SyncServerMethodRequest.Method # pylint: disable=no-member
|
Method = SyncServerMethodRequest.Method # pylint: disable=no-member
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import re
|
||||||
from typing import Collection, List, Match, Optional, Sequence
|
from typing import Collection, List, Match, Optional, Sequence
|
||||||
|
|
||||||
import anki # pylint: disable=unused-import
|
import anki # pylint: disable=unused-import
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
import anki.collection
|
import anki.collection
|
||||||
from anki.collection import OpChanges, OpChangesWithCount
|
from anki.collection import OpChanges, OpChangesWithCount
|
||||||
from anki.decks import DeckId
|
from anki.decks import DeckId
|
||||||
|
|
|
@ -32,7 +32,7 @@ from dataclasses import dataclass
|
||||||
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
|
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
|
||||||
|
|
||||||
import anki
|
import anki
|
||||||
import anki._backend.backend_pb2 as _pb
|
import anki.backend_pb2 as _pb
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.cards import Card
|
from anki.cards import Card
|
||||||
from anki.decks import DeckManager
|
from anki.decks import DeckManager
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
load("@bazel_skylib//lib:paths.bzl", "paths")
|
load("@bazel_skylib//lib:paths.bzl", "paths")
|
||||||
|
|
||||||
def _py_proto_library_impl(ctx):
|
def _py_proto_impl(ctx):
|
||||||
basename = ctx.file.src.basename
|
outs = []
|
||||||
outs = [
|
for src in ctx.files.srcs:
|
||||||
ctx.actions.declare_file(paths.replace_extension(basename, "_pb2.py")),
|
base = paths.basename(src.path)
|
||||||
ctx.actions.declare_file(paths.replace_extension(basename, "_pb2.pyi")),
|
outs.append(ctx.actions.declare_file(paths.replace_extension(base, "_pb2.py")))
|
||||||
]
|
outs.append(ctx.actions.declare_file(paths.replace_extension(base, "_pb2.pyi")))
|
||||||
|
|
||||||
ctx.actions.run(
|
ctx.actions.run(
|
||||||
outputs = outs,
|
outputs = outs,
|
||||||
inputs = [ctx.file.src],
|
inputs = ctx.files.srcs,
|
||||||
executable = ctx.executable.protoc_wrapper,
|
executable = ctx.executable.protoc_wrapper,
|
||||||
arguments = [
|
arguments = [
|
||||||
ctx.executable.protoc.path,
|
ctx.executable.protoc.path,
|
||||||
ctx.executable.mypy_protobuf.path,
|
ctx.executable.mypy_protobuf.path,
|
||||||
ctx.file.src.path,
|
|
||||||
paths.dirname(outs[0].path),
|
paths.dirname(outs[0].path),
|
||||||
],
|
] + [file.path for file in ctx.files.srcs],
|
||||||
tools = [
|
tools = [
|
||||||
ctx.executable.protoc,
|
ctx.executable.protoc,
|
||||||
ctx.executable.mypy_protobuf,
|
ctx.executable.mypy_protobuf,
|
||||||
|
@ -26,10 +26,10 @@ def _py_proto_library_impl(ctx):
|
||||||
DefaultInfo(files = depset(direct = outs), data_runfiles = ctx.runfiles(files = outs)),
|
DefaultInfo(files = depset(direct = outs), data_runfiles = ctx.runfiles(files = outs)),
|
||||||
]
|
]
|
||||||
|
|
||||||
py_proto_library_typed = rule(
|
py_proto = rule(
|
||||||
implementation = _py_proto_library_impl,
|
implementation = _py_proto_impl,
|
||||||
attrs = {
|
attrs = {
|
||||||
"src": attr.label(allow_single_file = [".proto"]),
|
"srcs": attr.label_list(allow_files = [".proto"]),
|
||||||
"protoc_wrapper": attr.label(
|
"protoc_wrapper": attr.label(
|
||||||
executable = True,
|
executable = True,
|
||||||
cfg = "exec",
|
cfg = "exec",
|
||||||
|
|
|
@ -10,16 +10,9 @@ import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
(protoc, mypy_protobuf, proto, outdir) = sys.argv[1:]
|
(protoc, mypy_protobuf, outdir, *protos) = sys.argv[1:]
|
||||||
|
|
||||||
# copy to current dir
|
prefix = "proto/"
|
||||||
basename = os.path.basename(proto)
|
|
||||||
shutil.copyfile(proto, basename)
|
|
||||||
|
|
||||||
# output filenames
|
|
||||||
without_ext = os.path.splitext(basename)[0]
|
|
||||||
pb2_py = without_ext + "_pb2.py"
|
|
||||||
pb2_pyi = without_ext + "_pb2.pyi"
|
|
||||||
|
|
||||||
# invoke protoc
|
# invoke protoc
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
|
@ -28,13 +21,17 @@ subprocess.run(
|
||||||
"--plugin=protoc-gen-mypy=" + mypy_protobuf,
|
"--plugin=protoc-gen-mypy=" + mypy_protobuf,
|
||||||
"--python_out=.",
|
"--python_out=.",
|
||||||
"--mypy_out=.",
|
"--mypy_out=.",
|
||||||
basename,
|
"-I" + prefix,
|
||||||
|
"-Iexternal/anki/" + prefix,
|
||||||
|
*protos,
|
||||||
],
|
],
|
||||||
# mypy prints to stderr on success :-(
|
# mypy prints to stderr on success :-(
|
||||||
stderr=subprocess.DEVNULL,
|
stderr=subprocess.DEVNULL,
|
||||||
check=True,
|
check=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# move files into output
|
for proto in protos:
|
||||||
shutil.move(pb2_py, outdir + "/" + pb2_py)
|
without_prefix_and_ext, _ = os.path.splitext(proto[len(prefix) :])
|
||||||
shutil.move(pb2_pyi, outdir + "/" + pb2_pyi)
|
for ext in "_pb2.py", "_pb2.pyi":
|
||||||
|
path = without_prefix_and_ext + ext
|
||||||
|
shutil.move(path, os.path.join(outdir, os.path.basename(path)))
|
||||||
|
|
|
@ -30,8 +30,8 @@ if subprocess.run(
|
||||||
"--",
|
"--",
|
||||||
"--config-file",
|
"--config-file",
|
||||||
"qt/mypy.ini",
|
"qt/mypy.ini",
|
||||||
"bazel-bin/qt/dmypy.runfiles/net_ankiweb_anki/pylib/anki",
|
"bazel-bin/qt/dmypy.runfiles/anki/pylib/anki",
|
||||||
"bazel-bin/qt/dmypy.runfiles/net_ankiweb_anki/qt/aqt",
|
"bazel-bin/qt/dmypy.runfiles/anki/qt/aqt",
|
||||||
"--python-executable",
|
"--python-executable",
|
||||||
os.path.abspath("pip/stubs/extendsitepkgs"),
|
os.path.abspath("pip/stubs/extendsitepkgs"),
|
||||||
],
|
],
|
||||||
|
|
|
@ -13,7 +13,7 @@ cargo_build_script(
|
||||||
name = "build_script",
|
name = "build_script",
|
||||||
srcs = glob(["build/*.rs"]),
|
srcs = glob(["build/*.rs"]),
|
||||||
build_script_env = {
|
build_script_env = {
|
||||||
"BACKEND_PROTO": "$(location //proto:backend.proto)",
|
"PROTO_TOP": "$(location //proto:.top_level)",
|
||||||
"PROTOC": "$(location @com_google_protobuf//:protoc)",
|
"PROTOC": "$(location @com_google_protobuf//:protoc)",
|
||||||
"RSLIB_FTL_ROOT": "$(location @rslib_ftl//:l10n.toml)",
|
"RSLIB_FTL_ROOT": "$(location @rslib_ftl//:l10n.toml)",
|
||||||
"EXTRA_FTL_ROOT": "$(location @extra_ftl//:l10n.toml)",
|
"EXTRA_FTL_ROOT": "$(location @extra_ftl//:l10n.toml)",
|
||||||
|
@ -22,9 +22,10 @@ cargo_build_script(
|
||||||
crate_root = "build/main.rs",
|
crate_root = "build/main.rs",
|
||||||
data = [
|
data = [
|
||||||
"//ftl",
|
"//ftl",
|
||||||
"//proto:backend.proto",
|
"//proto",
|
||||||
"@com_google_protobuf//:protoc",
|
"@com_google_protobuf//:protoc",
|
||||||
# bazel requires us to list these out separately
|
# bazel requires us to list these out separately
|
||||||
|
"//proto:.top_level",
|
||||||
"@rslib_ftl//:l10n.toml",
|
"@rslib_ftl//:l10n.toml",
|
||||||
"@extra_ftl//:l10n.toml",
|
"@extra_ftl//:l10n.toml",
|
||||||
],
|
],
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub trait Service {
|
||||||
write!(
|
write!(
|
||||||
buf,
|
buf,
|
||||||
concat!(" ",
|
concat!(" ",
|
||||||
"{idx} => {{ let input = {input_type}::decode(input)?;\n",
|
"{idx} => {{ let input = super::{input_type}::decode(input)?;\n",
|
||||||
"let output = self.{rust_method}(input)?;\n",
|
"let output = self.{rust_method}(input)?;\n",
|
||||||
"let mut out_bytes = Vec::new(); output.encode(&mut out_bytes)?; Ok(out_bytes) }}, "),
|
"let mut out_bytes = Vec::new(); output.encode(&mut out_bytes)?; Ok(out_bytes) }}, "),
|
||||||
idx = idx,
|
idx = idx,
|
||||||
|
@ -38,8 +38,8 @@ pub trait Service {
|
||||||
write!(
|
write!(
|
||||||
buf,
|
buf,
|
||||||
concat!(
|
concat!(
|
||||||
" fn {method_name}(&self, input: {input_type}) -> ",
|
" fn {method_name}(&self, input: super::{input_type}) -> ",
|
||||||
"Result<{output_type}>;\n"
|
"Result<super::{output_type}>;\n"
|
||||||
),
|
),
|
||||||
method_name = method.name,
|
method_name = method.name,
|
||||||
input_type = method.input_type,
|
input_type = method.input_type,
|
||||||
|
@ -55,7 +55,6 @@ impl prost_build::ServiceGenerator for CustomGenerator {
|
||||||
write!(
|
write!(
|
||||||
buf,
|
buf,
|
||||||
"pub mod {name}_service {{
|
"pub mod {name}_service {{
|
||||||
use super::*;
|
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
",
|
",
|
||||||
|
@ -73,16 +72,32 @@ fn service_generator() -> Box<dyn prost_build::ServiceGenerator> {
|
||||||
|
|
||||||
pub fn write_backend_proto_rs() {
|
pub fn write_backend_proto_rs() {
|
||||||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
let backend_proto;
|
let proto_dir = if let Ok(proto) = env::var("PROTO_TOP") {
|
||||||
let proto_dir;
|
let backend_proto = PathBuf::from(proto);
|
||||||
if let Ok(proto) = env::var("BACKEND_PROTO") {
|
backend_proto.parent().unwrap().to_owned()
|
||||||
backend_proto = PathBuf::from(proto);
|
|
||||||
proto_dir = backend_proto.parent().unwrap().to_owned();
|
|
||||||
} else {
|
} else {
|
||||||
backend_proto = PathBuf::from("backend.proto");
|
PathBuf::from("../proto")
|
||||||
proto_dir = PathBuf::from("../proto");
|
};
|
||||||
|
|
||||||
|
let subfolders = &["anki"];
|
||||||
|
let mut paths = vec![];
|
||||||
|
|
||||||
|
for subfolder in subfolders {
|
||||||
|
for entry in proto_dir.join(subfolder).read_dir().unwrap() {
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
let path = entry.path();
|
||||||
|
if path
|
||||||
|
.file_name()
|
||||||
|
.unwrap()
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.ends_with(".proto")
|
||||||
|
{
|
||||||
|
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
||||||
|
paths.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
println!("cargo:rerun-if-changed={}", backend_proto.to_str().unwrap());
|
|
||||||
|
|
||||||
let mut config = prost_build::Config::new();
|
let mut config = prost_build::Config::new();
|
||||||
config
|
config
|
||||||
|
@ -92,6 +107,6 @@ pub fn write_backend_proto_rs() {
|
||||||
"Deck.Filtered.SearchTerm.Order",
|
"Deck.Filtered.SearchTerm.Order",
|
||||||
"#[derive(strum::EnumIter)]",
|
"#[derive(strum::EnumIter)]",
|
||||||
)
|
)
|
||||||
.compile_protos(&[&backend_proto], &[&proto_dir, &out_dir])
|
.compile_protos(paths.as_slice(), &[proto_dir, out_dir])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/backend_proto.rs"));
|
pub mod backend {
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/anki.backend.rs"));
|
||||||
|
}
|
||||||
|
pub mod i18n {
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/anki.i18n.rs"));
|
||||||
|
}
|
||||||
|
pub mod generic {
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/anki.generic.rs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use backend::*;
|
||||||
|
pub use generic::*;
|
||||||
|
pub use i18n::*;
|
||||||
|
|
|
@ -52,7 +52,6 @@ ts_library(
|
||||||
deps = [
|
deps = [
|
||||||
"//ts/components",
|
"//ts/components",
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
"//ts/sveltelib",
|
"//ts/sveltelib",
|
||||||
"@npm//lodash-es",
|
"@npm//lodash-es",
|
||||||
"@npm//svelte",
|
"@npm//svelte",
|
||||||
|
@ -76,7 +75,6 @@ esbuild(
|
||||||
"@npm//bootstrap",
|
"@npm//bootstrap",
|
||||||
"@npm//marked",
|
"@npm//marked",
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
"//ts/sveltelib",
|
"//ts/sveltelib",
|
||||||
"//ts/components",
|
"//ts/components",
|
||||||
"//ts/components:svelte_components",
|
"//ts/components:svelte_components",
|
||||||
|
@ -123,7 +121,7 @@ jest_test(
|
||||||
protobuf = True,
|
protobuf = True,
|
||||||
deps = [
|
deps = [
|
||||||
":lib",
|
":lib",
|
||||||
"//ts/lib:backend_proto",
|
"//ts/lib",
|
||||||
"@npm//protobufjs",
|
"@npm//protobufjs",
|
||||||
"@npm//svelte",
|
"@npm//svelte",
|
||||||
],
|
],
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
@typescript-eslint/no-explicit-any: "off",
|
@typescript-eslint/no-explicit-any: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
import { ChangeNotetypeState, negativeOneToNull, MapContext } from "./lib";
|
import { ChangeNotetypeState, negativeOneToNull, MapContext } from "./lib";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
|
@ -64,15 +64,15 @@ const exampleInfoSame = {
|
||||||
|
|
||||||
function differentState(): ChangeNotetypeState {
|
function differentState(): ChangeNotetypeState {
|
||||||
return new ChangeNotetypeState(
|
return new ChangeNotetypeState(
|
||||||
pb.BackendProto.NotetypeNames.fromObject(exampleNames),
|
Backend.NotetypeNames.fromObject(exampleNames),
|
||||||
pb.BackendProto.ChangeNotetypeInfo.fromObject(exampleInfoDifferent)
|
Backend.ChangeNotetypeInfo.fromObject(exampleInfoDifferent)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sameState(): ChangeNotetypeState {
|
function sameState(): ChangeNotetypeState {
|
||||||
return new ChangeNotetypeState(
|
return new ChangeNotetypeState(
|
||||||
pb.BackendProto.NotetypeNames.fromObject(exampleNames),
|
Backend.NotetypeNames.fromObject(exampleNames),
|
||||||
pb.BackendProto.ChangeNotetypeInfo.fromObject(exampleInfoSame)
|
Backend.ChangeNotetypeInfo.fromObject(exampleInfoSame)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,22 +5,20 @@
|
||||||
@typescript-eslint/no-non-null-assertion: "off",
|
@typescript-eslint/no-non-null-assertion: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
import { postRequest } from "lib/postrequest";
|
import { postRequest } from "lib/postrequest";
|
||||||
import { readable, Readable } from "svelte/store";
|
import { readable, Readable } from "svelte/store";
|
||||||
import { isEqual } from "lodash-es";
|
import { isEqual } from "lodash-es";
|
||||||
|
|
||||||
export async function getNotetypeNames(): Promise<pb.BackendProto.NotetypeNames> {
|
export async function getNotetypeNames(): Promise<Backend.NotetypeNames> {
|
||||||
return pb.BackendProto.NotetypeNames.decode(
|
return Backend.NotetypeNames.decode(await postRequest("/_anki/notetypeNames", ""));
|
||||||
await postRequest("/_anki/notetypeNames", "")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getChangeNotetypeInfo(
|
export async function getChangeNotetypeInfo(
|
||||||
oldNotetypeId: number,
|
oldNotetypeId: number,
|
||||||
newNotetypeId: number
|
newNotetypeId: number
|
||||||
): Promise<pb.BackendProto.ChangeNotetypeInfo> {
|
): Promise<Backend.ChangeNotetypeInfo> {
|
||||||
return pb.BackendProto.ChangeNotetypeInfo.decode(
|
return Backend.ChangeNotetypeInfo.decode(
|
||||||
await postRequest(
|
await postRequest(
|
||||||
"/_anki/changeNotetypeInfo",
|
"/_anki/changeNotetypeInfo",
|
||||||
JSON.stringify({ oldNotetypeId, newNotetypeId })
|
JSON.stringify({ oldNotetypeId, newNotetypeId })
|
||||||
|
@ -29,10 +27,9 @@ export async function getChangeNotetypeInfo(
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function changeNotetype(
|
export async function changeNotetype(
|
||||||
input: pb.BackendProto.ChangeNotetypeRequest
|
input: Backend.ChangeNotetypeRequest
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const data: Uint8Array =
|
const data: Uint8Array = Backend.ChangeNotetypeRequest.encode(input).finish();
|
||||||
pb.BackendProto.ChangeNotetypeRequest.encode(input).finish();
|
|
||||||
await postRequest("/_anki/changeNotetype", data);
|
await postRequest("/_anki/changeNotetype", data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -50,9 +47,9 @@ export function negativeOneToNull(list: number[]): (number | null)[] {
|
||||||
export class ChangeNotetypeInfoWrapper {
|
export class ChangeNotetypeInfoWrapper {
|
||||||
fields: (number | null)[];
|
fields: (number | null)[];
|
||||||
templates?: (number | null)[];
|
templates?: (number | null)[];
|
||||||
readonly info: pb.BackendProto.ChangeNotetypeInfo;
|
readonly info: Backend.ChangeNotetypeInfo;
|
||||||
|
|
||||||
constructor(info: pb.BackendProto.ChangeNotetypeInfo) {
|
constructor(info: Backend.ChangeNotetypeInfo) {
|
||||||
this.info = info;
|
this.info = info;
|
||||||
const templates = info.input!.newTemplates!;
|
const templates = info.input!.newTemplates!;
|
||||||
if (templates.length > 0) {
|
if (templates.length > 0) {
|
||||||
|
@ -114,13 +111,13 @@ export class ChangeNotetypeInfoWrapper {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
input(): pb.BackendProto.ChangeNotetypeRequest {
|
input(): Backend.ChangeNotetypeRequest {
|
||||||
return this.info.input as pb.BackendProto.ChangeNotetypeRequest;
|
return this.info.input as Backend.ChangeNotetypeRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pack changes back into input message for saving.
|
/// Pack changes back into input message for saving.
|
||||||
intoInput(): pb.BackendProto.ChangeNotetypeRequest {
|
intoInput(): Backend.ChangeNotetypeRequest {
|
||||||
const input = this.info.input as pb.BackendProto.ChangeNotetypeRequest;
|
const input = this.info.input as Backend.ChangeNotetypeRequest;
|
||||||
input.newFields = nullToNegativeOne(this.fields);
|
input.newFields = nullToNegativeOne(this.fields);
|
||||||
if (this.templates) {
|
if (this.templates) {
|
||||||
input.newTemplates = nullToNegativeOne(this.templates);
|
input.newTemplates = nullToNegativeOne(this.templates);
|
||||||
|
@ -146,13 +143,10 @@ export class ChangeNotetypeState {
|
||||||
|
|
||||||
private info_: ChangeNotetypeInfoWrapper;
|
private info_: ChangeNotetypeInfoWrapper;
|
||||||
private infoSetter!: (val: ChangeNotetypeInfoWrapper) => void;
|
private infoSetter!: (val: ChangeNotetypeInfoWrapper) => void;
|
||||||
private notetypeNames: pb.BackendProto.NotetypeNames;
|
private notetypeNames: Backend.NotetypeNames;
|
||||||
private notetypesSetter!: (val: NotetypeListEntry[]) => void;
|
private notetypesSetter!: (val: NotetypeListEntry[]) => void;
|
||||||
|
|
||||||
constructor(
|
constructor(notetypes: Backend.NotetypeNames, info: Backend.ChangeNotetypeInfo) {
|
||||||
notetypes: pb.BackendProto.NotetypeNames,
|
|
||||||
info: pb.BackendProto.ChangeNotetypeInfo
|
|
||||||
) {
|
|
||||||
this.info_ = new ChangeNotetypeInfoWrapper(info);
|
this.info_ = new ChangeNotetypeInfoWrapper(info);
|
||||||
this.info = readable(this.info_, (set) => {
|
this.info = readable(this.info_, (set) => {
|
||||||
this.infoSetter = set;
|
this.infoSetter = set;
|
||||||
|
@ -203,7 +197,7 @@ export class ChangeNotetypeState {
|
||||||
await changeNotetype(this.dataForSaving());
|
await changeNotetype(this.dataForSaving());
|
||||||
}
|
}
|
||||||
|
|
||||||
dataForSaving(): pb.BackendProto.ChangeNotetypeRequest {
|
dataForSaving(): Backend.ChangeNotetypeRequest {
|
||||||
return this.info_.intoInput();
|
return this.info_.intoInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ def compile_sass(group, srcs, deps = [], visibility = ["//visibility:private"]):
|
||||||
sourcemap = False,
|
sourcemap = False,
|
||||||
deps = deps,
|
deps = deps,
|
||||||
visibility = visibility,
|
visibility = visibility,
|
||||||
include_paths = ["external/net_ankiweb_anki"],
|
include_paths = ["external/anki"],
|
||||||
)
|
)
|
||||||
|
|
||||||
native.filegroup(
|
native.filegroup(
|
||||||
|
|
|
@ -17,25 +17,24 @@ filegroup(
|
||||||
compile_svelte(
|
compile_svelte(
|
||||||
name = "svelte",
|
name = "svelte",
|
||||||
srcs = svelte_files,
|
srcs = svelte_files,
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//ts/sass:button_mixins_lib",
|
"//ts/sass:button_mixins_lib",
|
||||||
"//ts/sass/bootstrap",
|
"//ts/sass/bootstrap",
|
||||||
],
|
],
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ts_library(
|
ts_library(
|
||||||
name = "components",
|
name = "components",
|
||||||
module_name = "components",
|
|
||||||
srcs = glob(
|
srcs = glob(
|
||||||
["*.ts"],
|
["*.ts"],
|
||||||
exclude = ["*.test.ts"],
|
exclude = ["*.test.ts"],
|
||||||
),
|
),
|
||||||
|
module_name = "components",
|
||||||
tsconfig = "//ts:tsconfig.json",
|
tsconfig = "//ts:tsconfig.json",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
"//ts/sveltelib",
|
"//ts/sveltelib",
|
||||||
"@npm//@popperjs/core",
|
"@npm//@popperjs/core",
|
||||||
"@npm//@types/bootstrap",
|
"@npm//@types/bootstrap",
|
||||||
|
|
|
@ -35,10 +35,7 @@ ts_library(
|
||||||
ts_library(
|
ts_library(
|
||||||
name = "lib",
|
name = "lib",
|
||||||
srcs = ["lib.ts"],
|
srcs = ["lib.ts"],
|
||||||
deps = [
|
deps = ["//ts/lib"],
|
||||||
"//ts/lib",
|
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
esbuild(
|
esbuild(
|
||||||
|
@ -56,7 +53,6 @@ esbuild(
|
||||||
":base_css",
|
":base_css",
|
||||||
":index",
|
":index",
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
"@npm//protobufjs",
|
"@npm//protobufjs",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,11 +3,11 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
import { buildNextLearnMsg } from "./lib";
|
import { buildNextLearnMsg } from "./lib";
|
||||||
import { bridgeLink } from "lib/bridgecommand";
|
import { bridgeLink } from "lib/bridgecommand";
|
||||||
|
|
||||||
export let info: pb.BackendProto.CongratsInfoResponse;
|
export let info: Backend.CongratsInfoResponse;
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
|
|
||||||
const congrats = tr.schedulingCongratulationsFinished();
|
const congrats = tr.schedulingCongratulationsFinished();
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
import pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
import { postRequest } from "lib/postrequest";
|
import { postRequest } from "lib/postrequest";
|
||||||
import { naturalUnit, unitAmount, unitName } from "lib/time";
|
import { naturalUnit, unitAmount, unitName } from "lib/time";
|
||||||
|
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
|
|
||||||
export async function getCongratsInfo(): Promise<pb.BackendProto.CongratsInfoResponse> {
|
export async function getCongratsInfo(): Promise<Backend.CongratsInfoResponse> {
|
||||||
return pb.BackendProto.CongratsInfoResponse.decode(
|
return Backend.CongratsInfoResponse.decode(
|
||||||
await postRequest("/_anki/congratsInfo", "")
|
await postRequest("/_anki/congratsInfo", "")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildNextLearnMsg(info: pb.BackendProto.CongratsInfoResponse): string {
|
export function buildNextLearnMsg(info: Backend.CongratsInfoResponse): string {
|
||||||
const secsUntil = info.secsUntilNextLearn;
|
const secsUntil = info.secsUntilNextLearn;
|
||||||
// next learning card not due (/ until tomorrow)?
|
// next learning card not due (/ until tomorrow)?
|
||||||
if (secsUntil == 0 || secsUntil > 86_400) {
|
if (secsUntil == 0 || secsUntil > 86_400) {
|
||||||
|
|
|
@ -68,7 +68,6 @@ ts_library(
|
||||||
"//ts:image_module_support",
|
"//ts:image_module_support",
|
||||||
"//ts/components",
|
"//ts/components",
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
"//ts/sveltelib",
|
"//ts/sveltelib",
|
||||||
"@npm//lodash-es",
|
"@npm//lodash-es",
|
||||||
"@npm//svelte",
|
"@npm//svelte",
|
||||||
|
@ -94,7 +93,6 @@ esbuild(
|
||||||
"@npm//marked",
|
"@npm//marked",
|
||||||
"@npm//protobufjs",
|
"@npm//protobufjs",
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
"//ts/sveltelib",
|
"//ts/sveltelib",
|
||||||
"//ts/components",
|
"//ts/components",
|
||||||
"//ts/components:svelte_components",
|
"//ts/components:svelte_components",
|
||||||
|
@ -141,7 +139,7 @@ jest_test(
|
||||||
protobuf = True,
|
protobuf = True,
|
||||||
deps = [
|
deps = [
|
||||||
":lib",
|
":lib",
|
||||||
"//ts/lib:backend_proto",
|
"//ts/lib",
|
||||||
"@npm//protobufjs",
|
"@npm//protobufjs",
|
||||||
"@npm//svelte",
|
"@npm//svelte",
|
||||||
],
|
],
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
@typescript-eslint/no-explicit-any: "off",
|
@typescript-eslint/no-explicit-any: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
import { DeckOptionsState } from "./lib";
|
import { DeckOptionsState } from "./lib";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ const exampleData = {
|
||||||
function startingState(): DeckOptionsState {
|
function startingState(): DeckOptionsState {
|
||||||
return new DeckOptionsState(
|
return new DeckOptionsState(
|
||||||
123,
|
123,
|
||||||
pb.BackendProto.DeckConfigsForUpdate.fromObject(exampleData)
|
Backend.DeckConfigsForUpdate.fromObject(exampleData)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
@typescript-eslint/no-non-null-assertion: "off",
|
@typescript-eslint/no-non-null-assertion: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
import { postRequest } from "lib/postrequest";
|
import { postRequest } from "lib/postrequest";
|
||||||
import { Writable, writable, get, Readable, readable } from "svelte/store";
|
import { Writable, writable, get, Readable, readable } from "svelte/store";
|
||||||
import { isEqual, cloneDeep } from "lodash-es";
|
import { isEqual, cloneDeep } from "lodash-es";
|
||||||
|
@ -14,17 +14,16 @@ import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent";
|
||||||
|
|
||||||
export async function getDeckOptionsInfo(
|
export async function getDeckOptionsInfo(
|
||||||
deckId: number
|
deckId: number
|
||||||
): Promise<pb.BackendProto.DeckConfigsForUpdate> {
|
): Promise<Backend.DeckConfigsForUpdate> {
|
||||||
return pb.BackendProto.DeckConfigsForUpdate.decode(
|
return Backend.DeckConfigsForUpdate.decode(
|
||||||
await postRequest("/_anki/deckConfigsForUpdate", JSON.stringify({ deckId }))
|
await postRequest("/_anki/deckConfigsForUpdate", JSON.stringify({ deckId }))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveDeckOptions(
|
export async function saveDeckOptions(
|
||||||
input: pb.BackendProto.UpdateDeckConfigsRequest
|
input: Backend.UpdateDeckConfigsRequest
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const data: Uint8Array =
|
const data: Uint8Array = Backend.UpdateDeckConfigsRequest.encode(input).finish();
|
||||||
pb.BackendProto.UpdateDeckConfigsRequest.encode(input).finish();
|
|
||||||
await postRequest("/_anki/updateDeckConfigs", data);
|
await postRequest("/_anki/updateDeckConfigs", data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -32,7 +31,7 @@ export async function saveDeckOptions(
|
||||||
export type DeckOptionsId = number;
|
export type DeckOptionsId = number;
|
||||||
|
|
||||||
export interface ConfigWithCount {
|
export interface ConfigWithCount {
|
||||||
config: pb.BackendProto.DeckConfig;
|
config: Backend.DeckConfig;
|
||||||
useCount: number;
|
useCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,14 +48,14 @@ export interface ConfigListEntry {
|
||||||
current: boolean;
|
current: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigInner = pb.BackendProto.DeckConfig.Config;
|
type ConfigInner = Backend.DeckConfig.Config;
|
||||||
export class DeckOptionsState {
|
export class DeckOptionsState {
|
||||||
readonly currentConfig: Writable<ConfigInner>;
|
readonly currentConfig: Writable<ConfigInner>;
|
||||||
readonly currentAuxData: Writable<Record<string, unknown>>;
|
readonly currentAuxData: Writable<Record<string, unknown>>;
|
||||||
readonly configList: Readable<ConfigListEntry[]>;
|
readonly configList: Readable<ConfigListEntry[]>;
|
||||||
readonly parentLimits: Readable<ParentLimits>;
|
readonly parentLimits: Readable<ParentLimits>;
|
||||||
readonly cardStateCustomizer: Writable<string>;
|
readonly cardStateCustomizer: Writable<string>;
|
||||||
readonly currentDeck: pb.BackendProto.DeckConfigsForUpdate.CurrentDeck;
|
readonly currentDeck: Backend.DeckConfigsForUpdate.CurrentDeck;
|
||||||
readonly defaults: ConfigInner;
|
readonly defaults: ConfigInner;
|
||||||
readonly addonComponents: Writable<DynamicSvelteComponent[]>;
|
readonly addonComponents: Writable<DynamicSvelteComponent[]>;
|
||||||
readonly v3Scheduler: boolean;
|
readonly v3Scheduler: boolean;
|
||||||
|
@ -71,13 +70,12 @@ export class DeckOptionsState {
|
||||||
private removedConfigs: DeckOptionsId[] = [];
|
private removedConfigs: DeckOptionsId[] = [];
|
||||||
private schemaModified: boolean;
|
private schemaModified: boolean;
|
||||||
|
|
||||||
constructor(targetDeckId: number, data: pb.BackendProto.DeckConfigsForUpdate) {
|
constructor(targetDeckId: number, data: Backend.DeckConfigsForUpdate) {
|
||||||
this.targetDeckId = targetDeckId;
|
this.targetDeckId = targetDeckId;
|
||||||
this.currentDeck =
|
this.currentDeck = data.currentDeck as Backend.DeckConfigsForUpdate.CurrentDeck;
|
||||||
data.currentDeck as pb.BackendProto.DeckConfigsForUpdate.CurrentDeck;
|
|
||||||
this.defaults = data.defaults!.config! as ConfigInner;
|
this.defaults = data.defaults!.config! as ConfigInner;
|
||||||
this.configs = data.allConfig.map((config) => {
|
this.configs = data.allConfig.map((config) => {
|
||||||
const configInner = config.config as pb.BackendProto.DeckConfig;
|
const configInner = config.config as Backend.DeckConfig;
|
||||||
return {
|
return {
|
||||||
config: configInner,
|
config: configInner,
|
||||||
useCount: config.useCount!,
|
useCount: config.useCount!,
|
||||||
|
@ -152,12 +150,9 @@ export class DeckOptionsState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clone the current config, making it current.
|
/// Clone the current config, making it current.
|
||||||
private addConfigFrom(
|
private addConfigFrom(name: string, source: Backend.DeckConfig.IConfig): void {
|
||||||
name: string,
|
|
||||||
source: pb.BackendProto.DeckConfig.IConfig
|
|
||||||
): void {
|
|
||||||
const uniqueName = this.ensureNewNameUnique(name);
|
const uniqueName = this.ensureNewNameUnique(name);
|
||||||
const config = pb.BackendProto.DeckConfig.create({
|
const config = Backend.DeckConfig.create({
|
||||||
id: 0,
|
id: 0,
|
||||||
name: uniqueName,
|
name: uniqueName,
|
||||||
config: cloneDeep(source),
|
config: cloneDeep(source),
|
||||||
|
@ -193,7 +188,7 @@ export class DeckOptionsState {
|
||||||
this.updateConfigList();
|
this.updateConfigList();
|
||||||
}
|
}
|
||||||
|
|
||||||
dataForSaving(applyToChildren: boolean): pb.BackendProto.UpdateDeckConfigsRequest {
|
dataForSaving(applyToChildren: boolean): Backend.UpdateDeckConfigsRequest {
|
||||||
const modifiedConfigsExcludingCurrent = this.configs
|
const modifiedConfigsExcludingCurrent = this.configs
|
||||||
.map((c) => c.config)
|
.map((c) => c.config)
|
||||||
.filter((c, idx) => {
|
.filter((c, idx) => {
|
||||||
|
@ -207,7 +202,7 @@ export class DeckOptionsState {
|
||||||
// current must come last, even if unmodified
|
// current must come last, even if unmodified
|
||||||
this.configs[this.selectedIdx].config,
|
this.configs[this.selectedIdx].config,
|
||||||
];
|
];
|
||||||
return pb.BackendProto.UpdateDeckConfigsRequest.create({
|
return Backend.UpdateDeckConfigsRequest.create({
|
||||||
targetDeckId: this.targetDeckId,
|
targetDeckId: this.targetDeckId,
|
||||||
removedConfigIds: this.removedConfigs,
|
removedConfigIds: this.removedConfigs,
|
||||||
configs,
|
configs,
|
||||||
|
|
|
@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
import type { PreferenceStore } from "sveltelib/preferences";
|
import type { PreferenceStore } from "sveltelib/preferences";
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
|
|
||||||
|
@ -19,9 +19,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import { gatherData, buildHistogram } from "./added";
|
import { gatherData, buildHistogram } from "./added";
|
||||||
import type { GraphData } from "./added";
|
import type { GraphData } from "./added";
|
||||||
|
|
||||||
export let sourceData: pb.BackendProto.GraphsResponse | null = null;
|
export let sourceData: Backend.GraphsResponse | null = null;
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
export let preferences: PreferenceStore<pb.BackendProto.GraphPreferences>;
|
export let preferences: PreferenceStore<Backend.GraphPreferences>;
|
||||||
|
|
||||||
let histogramData = null as HistogramData | null;
|
let histogramData = null as HistogramData | null;
|
||||||
let tableData: TableDatum[] = [];
|
let tableData: TableDatum[] = [];
|
||||||
|
|
|
@ -45,7 +45,6 @@ ts_library(
|
||||||
),
|
),
|
||||||
deps = [
|
deps = [
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
"//ts/sveltelib",
|
"//ts/sveltelib",
|
||||||
"@npm//@types/d3",
|
"@npm//@types/d3",
|
||||||
"@npm//@types/lodash",
|
"@npm//@types/lodash",
|
||||||
|
@ -68,7 +67,6 @@ esbuild(
|
||||||
deps = [
|
deps = [
|
||||||
"//ts/sveltelib",
|
"//ts/sveltelib",
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
":index",
|
":index",
|
||||||
":base_css",
|
":base_css",
|
||||||
"@npm//protobufjs",
|
"@npm//protobufjs",
|
||||||
|
|
|
@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
|
|
||||||
import Graph from "./Graph.svelte";
|
import Graph from "./Graph.svelte";
|
||||||
import InputBox from "./InputBox.svelte";
|
import InputBox from "./InputBox.svelte";
|
||||||
|
@ -14,7 +14,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import { renderButtons } from "./buttons";
|
import { renderButtons } from "./buttons";
|
||||||
import { defaultGraphBounds, GraphRange, RevlogRange } from "./graph-helpers";
|
import { defaultGraphBounds, GraphRange, RevlogRange } from "./graph-helpers";
|
||||||
|
|
||||||
export let sourceData: pb.BackendProto.GraphsResponse | null = null;
|
export let sourceData: Backend.GraphsResponse | null = null;
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
export let revlogRange: RevlogRange;
|
export let revlogRange: RevlogRange;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
import type { PreferenceStore } from "sveltelib/preferences";
|
import type { PreferenceStore } from "sveltelib/preferences";
|
||||||
|
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
|
@ -18,8 +18,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import { gatherData, renderCalendar } from "./calendar";
|
import { gatherData, renderCalendar } from "./calendar";
|
||||||
import type { GraphData } from "./calendar";
|
import type { GraphData } from "./calendar";
|
||||||
|
|
||||||
export let sourceData: pb.BackendProto.GraphsResponse;
|
export let sourceData: Backend.GraphsResponse;
|
||||||
export let preferences: PreferenceStore<pb.BackendProto.GraphPreferences>;
|
export let preferences: PreferenceStore<Backend.GraphPreferences>;
|
||||||
export let revlogRange: RevlogRange;
|
export let revlogRange: RevlogRange;
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
export let nightMode: boolean;
|
export let nightMode: boolean;
|
||||||
|
|
|
@ -4,7 +4,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
import type { PreferenceStore } from "sveltelib/preferences";
|
import type { PreferenceStore } from "sveltelib/preferences";
|
||||||
|
|
||||||
import Graph from "./Graph.svelte";
|
import Graph from "./Graph.svelte";
|
||||||
|
@ -15,9 +15,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import { gatherData, renderCards } from "./card-counts";
|
import { gatherData, renderCards } from "./card-counts";
|
||||||
import type { GraphData, TableDatum } from "./card-counts";
|
import type { GraphData, TableDatum } from "./card-counts";
|
||||||
|
|
||||||
export let sourceData: pb.BackendProto.GraphsResponse;
|
export let sourceData: Backend.GraphsResponse;
|
||||||
import * as tr2 from "lib/i18n";
|
import * as tr2 from "lib/i18n";
|
||||||
export let preferences: PreferenceStore<pb.BackendProto.GraphPreferences>;
|
export let preferences: PreferenceStore<Backend.GraphPreferences>;
|
||||||
|
|
||||||
let { cardCountsSeparateInactive, browserLinksSupported } = preferences;
|
let { cardCountsSeparateInactive, browserLinksSupported } = preferences;
|
||||||
const dispatch = createEventDispatcher<SearchEventMap>();
|
const dispatch = createEventDispatcher<SearchEventMap>();
|
||||||
|
|
|
@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
import type { PreferenceStore } from "sveltelib/preferences";
|
import type { PreferenceStore } from "sveltelib/preferences";
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import { gatherData, prepareData } from "./ease";
|
import { gatherData, prepareData } from "./ease";
|
||||||
import type { TableDatum, SearchEventMap } from "./graph-helpers";
|
import type { TableDatum, SearchEventMap } from "./graph-helpers";
|
||||||
|
|
||||||
export let sourceData: pb.BackendProto.GraphsResponse | null = null;
|
export let sourceData: Backend.GraphsResponse | null = null;
|
||||||
export let preferences: PreferenceStore<pb.BackendProto.GraphPreferences>;
|
export let preferences: PreferenceStore<Backend.GraphPreferences>;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<SearchEventMap>();
|
const dispatch = createEventDispatcher<SearchEventMap>();
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
|
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
|
|
||||||
import Graph from "./Graph.svelte";
|
import Graph from "./Graph.svelte";
|
||||||
import InputBox from "./InputBox.svelte";
|
import InputBox from "./InputBox.svelte";
|
||||||
|
@ -20,9 +20,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import { gatherData, buildHistogram } from "./future-due";
|
import { gatherData, buildHistogram } from "./future-due";
|
||||||
import type { GraphData } from "./future-due";
|
import type { GraphData } from "./future-due";
|
||||||
|
|
||||||
export let sourceData: pb.BackendProto.GraphsResponse | null = null;
|
export let sourceData: Backend.GraphsResponse | null = null;
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
export let preferences: PreferenceStore<pb.BackendProto.GraphPreferences>;
|
export let preferences: PreferenceStore<Backend.GraphPreferences>;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<SearchEventMap>();
|
const dispatch = createEventDispatcher<SearchEventMap>();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
|
|
||||||
import Graph from "./Graph.svelte";
|
import Graph from "./Graph.svelte";
|
||||||
import InputBox from "./InputBox.svelte";
|
import InputBox from "./InputBox.svelte";
|
||||||
|
@ -15,7 +15,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import { defaultGraphBounds, RevlogRange, GraphRange } from "./graph-helpers";
|
import { defaultGraphBounds, RevlogRange, GraphRange } from "./graph-helpers";
|
||||||
import { renderHours } from "./hours";
|
import { renderHours } from "./hours";
|
||||||
|
|
||||||
export let sourceData: pb.BackendProto.GraphsResponse | null = null;
|
export let sourceData: Backend.GraphsResponse | null = null;
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
export let revlogRange: RevlogRange;
|
export let revlogRange: RevlogRange;
|
||||||
let graphRange: GraphRange = GraphRange.Year;
|
let graphRange: GraphRange = GraphRange.Year;
|
||||||
|
|
|
@ -5,7 +5,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { timeSpan, MONTH } from "lib/time";
|
import { timeSpan, MONTH } from "lib/time";
|
||||||
|
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
import type { PreferenceStore } from "sveltelib/preferences";
|
import type { PreferenceStore } from "sveltelib/preferences";
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
|
|
||||||
|
@ -23,9 +23,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import type { IntervalGraphData } from "./intervals";
|
import type { IntervalGraphData } from "./intervals";
|
||||||
import type { TableDatum, SearchEventMap } from "./graph-helpers";
|
import type { TableDatum, SearchEventMap } from "./graph-helpers";
|
||||||
|
|
||||||
export let sourceData: pb.BackendProto.GraphsResponse | null = null;
|
export let sourceData: Backend.GraphsResponse | null = null;
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
export let preferences: PreferenceStore<pb.BackendProto.GraphPreferences>;
|
export let preferences: PreferenceStore<Backend.GraphPreferences>;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<SearchEventMap>();
|
const dispatch = createEventDispatcher<SearchEventMap>();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
|
|
||||||
import Graph from "./Graph.svelte";
|
import Graph from "./Graph.svelte";
|
||||||
import InputBox from "./InputBox.svelte";
|
import InputBox from "./InputBox.svelte";
|
||||||
|
@ -19,7 +19,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import { gatherData, renderReviews } from "./reviews";
|
import { gatherData, renderReviews } from "./reviews";
|
||||||
import type { GraphData } from "./reviews";
|
import type { GraphData } from "./reviews";
|
||||||
|
|
||||||
export let sourceData: pb.BackendProto.GraphsResponse | null = null;
|
export let sourceData: Backend.GraphsResponse | null = null;
|
||||||
export let revlogRange: RevlogRange;
|
export let revlogRange: RevlogRange;
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,14 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
|
|
||||||
import Graph from "./Graph.svelte";
|
import Graph from "./Graph.svelte";
|
||||||
|
|
||||||
import type { TodayData } from "./today";
|
import type { TodayData } from "./today";
|
||||||
import { gatherData } from "./today";
|
import { gatherData } from "./today";
|
||||||
|
|
||||||
export let sourceData: pb.BackendProto.GraphsResponse | null = null;
|
export let sourceData: Backend.GraphsResponse | null = null;
|
||||||
|
|
||||||
let todayData: TodayData | null = null;
|
let todayData: TodayData | null = null;
|
||||||
$: if (sourceData) {
|
$: if (sourceData) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import type { Writable } from "svelte/store";
|
import type { Writable } from "svelte/store";
|
||||||
import type { PreferenceRaw, PreferencePayload } from "sveltelib/preferences";
|
import type { PreferenceRaw, PreferencePayload } from "sveltelib/preferences";
|
||||||
|
|
||||||
import pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
import { postRequest } from "lib/postrequest";
|
import { postRequest } from "lib/postrequest";
|
||||||
|
|
||||||
import useAsync from "sveltelib/async";
|
import useAsync from "sveltelib/async";
|
||||||
|
@ -21,24 +21,24 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
async function getGraphData(
|
async function getGraphData(
|
||||||
search: string,
|
search: string,
|
||||||
days: number
|
days: number
|
||||||
): Promise<pb.BackendProto.GraphsResponse> {
|
): Promise<Backend.GraphsResponse> {
|
||||||
return pb.BackendProto.GraphsResponse.decode(
|
return Backend.GraphsResponse.decode(
|
||||||
await postRequest("/_anki/graphData", JSON.stringify({ search, days }))
|
await postRequest("/_anki/graphData", JSON.stringify({ search, days }))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getGraphPreferences(): Promise<pb.BackendProto.GraphPreferences> {
|
async function getGraphPreferences(): Promise<Backend.GraphPreferences> {
|
||||||
return pb.BackendProto.GraphPreferences.decode(
|
return Backend.GraphPreferences.decode(
|
||||||
await postRequest("/_anki/graphPreferences", JSON.stringify({}))
|
await postRequest("/_anki/graphPreferences", JSON.stringify({}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setGraphPreferences(
|
async function setGraphPreferences(
|
||||||
prefs: PreferencePayload<pb.BackendProto.GraphPreferences>
|
prefs: PreferencePayload<Backend.GraphPreferences>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await postRequest(
|
await postRequest(
|
||||||
"/_anki/setGraphPreferences",
|
"/_anki/setGraphPreferences",
|
||||||
pb.BackendProto.GraphPreferences.encode(prefs).finish()
|
Backend.GraphPreferences.encode(prefs).finish()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,12 +56,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
getPreferences(
|
getPreferences(
|
||||||
getGraphPreferences,
|
getGraphPreferences,
|
||||||
setGraphPreferences,
|
setGraphPreferences,
|
||||||
pb.BackendProto.GraphPreferences.toObject.bind(
|
Backend.GraphPreferences.toObject.bind(Backend.GraphPreferences) as (
|
||||||
pb.BackendProto.GraphPreferences
|
preferences: Backend.GraphPreferences,
|
||||||
) as (
|
|
||||||
preferences: pb.BackendProto.GraphPreferences,
|
|
||||||
options: { defaults: boolean }
|
options: { defaults: boolean }
|
||||||
) => PreferenceRaw<pb.BackendProto.GraphPreferences>
|
) => PreferenceRaw<Backend.GraphPreferences>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
@typescript-eslint/no-explicit-any: "off",
|
@typescript-eslint/no-explicit-any: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
extent,
|
extent,
|
||||||
|
@ -28,8 +28,8 @@ export interface GraphData {
|
||||||
daysAdded: number[];
|
daysAdded: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gatherData(data: pb.BackendProto.GraphsResponse): GraphData {
|
export function gatherData(data: Backend.GraphsResponse): GraphData {
|
||||||
const daysAdded = (data.cards as pb.BackendProto.Card[]).map((card) => {
|
const daysAdded = (data.cards as Backend.Card[]).map((card) => {
|
||||||
const elapsedSecs = (card.id as number) / 1000 - data.nextDayAtSecs;
|
const elapsedSecs = (card.id as number) / 1000 - data.nextDayAtSecs;
|
||||||
return Math.ceil(elapsedSecs / 86400);
|
return Math.ceil(elapsedSecs / 86400);
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
@typescript-eslint/no-explicit-any: "off",
|
@typescript-eslint/no-explicit-any: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
interpolateRdYlGn,
|
interpolateRdYlGn,
|
||||||
|
@ -36,18 +36,15 @@ export interface GraphData {
|
||||||
mature: ButtonCounts;
|
mature: ButtonCounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ReviewKind = pb.BackendProto.RevlogEntry.ReviewKind;
|
const ReviewKind = Backend.RevlogEntry.ReviewKind;
|
||||||
|
|
||||||
export function gatherData(
|
export function gatherData(data: Backend.GraphsResponse, range: GraphRange): GraphData {
|
||||||
data: pb.BackendProto.GraphsResponse,
|
|
||||||
range: GraphRange
|
|
||||||
): GraphData {
|
|
||||||
const cutoff = millisecondCutoffForRange(range, data.nextDayAtSecs);
|
const cutoff = millisecondCutoffForRange(range, data.nextDayAtSecs);
|
||||||
const learning: ButtonCounts = [0, 0, 0, 0];
|
const learning: ButtonCounts = [0, 0, 0, 0];
|
||||||
const young: ButtonCounts = [0, 0, 0, 0];
|
const young: ButtonCounts = [0, 0, 0, 0];
|
||||||
const mature: ButtonCounts = [0, 0, 0, 0];
|
const mature: ButtonCounts = [0, 0, 0, 0];
|
||||||
|
|
||||||
for (const review of data.revlog as pb.BackendProto.RevlogEntry[]) {
|
for (const review of data.revlog as Backend.RevlogEntry[]) {
|
||||||
if (cutoff && (review.id as number) < cutoff) {
|
if (cutoff && (review.id as number) < cutoff) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +96,7 @@ interface TotalCorrect {
|
||||||
export function renderButtons(
|
export function renderButtons(
|
||||||
svgElem: SVGElement,
|
svgElem: SVGElement,
|
||||||
bounds: GraphBounds,
|
bounds: GraphBounds,
|
||||||
origData: pb.BackendProto.GraphsResponse,
|
origData: Backend.GraphsResponse,
|
||||||
range: GraphRange
|
range: GraphRange
|
||||||
): void {
|
): void {
|
||||||
const sourceData = gatherData(origData, range);
|
const sourceData = gatherData(origData, range);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
@typescript-eslint/no-non-null-assertion: "off",
|
@typescript-eslint/no-non-null-assertion: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
import {
|
import {
|
||||||
interpolateBlues,
|
interpolateBlues,
|
||||||
select,
|
select,
|
||||||
|
@ -49,16 +49,16 @@ interface DayDatum {
|
||||||
date: Date;
|
date: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
type WeekdayType = pb.BackendProto.GraphPreferences.Weekday;
|
type WeekdayType = Backend.GraphPreferences.Weekday;
|
||||||
const Weekday = pb.BackendProto.GraphPreferences.Weekday; /* enum */
|
const Weekday = Backend.GraphPreferences.Weekday; /* enum */
|
||||||
|
|
||||||
export function gatherData(
|
export function gatherData(
|
||||||
data: pb.BackendProto.GraphsResponse,
|
data: Backend.GraphsResponse,
|
||||||
firstDayOfWeek: WeekdayType
|
firstDayOfWeek: WeekdayType
|
||||||
): GraphData {
|
): GraphData {
|
||||||
const reviewCount = new Map<number, number>();
|
const reviewCount = new Map<number, number>();
|
||||||
|
|
||||||
for (const review of data.revlog as pb.BackendProto.RevlogEntry[]) {
|
for (const review of data.revlog as Backend.RevlogEntry[]) {
|
||||||
if (review.buttonChosen == 0) {
|
if (review.buttonChosen == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { CardQueue, CardType } from "lib/cards";
|
import { CardQueue, CardType } from "lib/cards";
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
import {
|
import {
|
||||||
schemeGreens,
|
schemeGreens,
|
||||||
schemeBlues,
|
schemeBlues,
|
||||||
|
@ -41,10 +41,7 @@ const barColours = [
|
||||||
"grey" /* buried */,
|
"grey" /* buried */,
|
||||||
];
|
];
|
||||||
|
|
||||||
function countCards(
|
function countCards(cards: Backend.ICard[], separateInactive: boolean): Count[] {
|
||||||
cards: pb.BackendProto.ICard[],
|
|
||||||
separateInactive: boolean
|
|
||||||
): Count[] {
|
|
||||||
let newCards = 0;
|
let newCards = 0;
|
||||||
let learn = 0;
|
let learn = 0;
|
||||||
let relearn = 0;
|
let relearn = 0;
|
||||||
|
@ -53,7 +50,7 @@ function countCards(
|
||||||
let suspended = 0;
|
let suspended = 0;
|
||||||
let buried = 0;
|
let buried = 0;
|
||||||
|
|
||||||
for (const card of cards as pb.BackendProto.Card[]) {
|
for (const card of cards as Backend.Card[]) {
|
||||||
if (separateInactive) {
|
if (separateInactive) {
|
||||||
switch (card.queue) {
|
switch (card.queue) {
|
||||||
case CardQueue.Suspended:
|
case CardQueue.Suspended:
|
||||||
|
@ -127,7 +124,7 @@ function countCards(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gatherData(
|
export function gatherData(
|
||||||
data: pb.BackendProto.GraphsResponse,
|
data: Backend.GraphsResponse,
|
||||||
separateInactive: boolean
|
separateInactive: boolean
|
||||||
): GraphData {
|
): GraphData {
|
||||||
const totalCards = data.cards.length;
|
const totalCards = data.cards.length;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
@typescript-eslint/no-explicit-any: "off",
|
@typescript-eslint/no-explicit-any: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
import {
|
import {
|
||||||
extent,
|
extent,
|
||||||
histogram,
|
histogram,
|
||||||
|
@ -26,8 +26,8 @@ export interface GraphData {
|
||||||
eases: number[];
|
eases: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gatherData(data: pb.BackendProto.GraphsResponse): GraphData {
|
export function gatherData(data: Backend.GraphsResponse): GraphData {
|
||||||
const eases = (data.cards as pb.BackendProto.Card[])
|
const eases = (data.cards as Backend.Card[])
|
||||||
.filter((c) => [CardType.Review, CardType.Relearn].includes(c.ctype))
|
.filter((c) => [CardType.Review, CardType.Relearn].includes(c.ctype))
|
||||||
.map((c) => c.easeFactor / 10);
|
.map((c) => c.easeFactor / 10);
|
||||||
return { eases };
|
return { eases };
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
@typescript-eslint/no-explicit-any: "off",
|
@typescript-eslint/no-explicit-any: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
import {
|
import {
|
||||||
extent,
|
extent,
|
||||||
histogram,
|
histogram,
|
||||||
|
@ -30,13 +30,13 @@ export interface GraphData {
|
||||||
haveBacklog: boolean;
|
haveBacklog: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gatherData(data: pb.BackendProto.GraphsResponse): GraphData {
|
export function gatherData(data: Backend.GraphsResponse): GraphData {
|
||||||
const isLearning = (card: pb.BackendProto.Card): boolean =>
|
const isLearning = (card: Backend.Card): boolean =>
|
||||||
[CardQueue.Learn, CardQueue.PreviewRepeat].includes(card.queue);
|
[CardQueue.Learn, CardQueue.PreviewRepeat].includes(card.queue);
|
||||||
|
|
||||||
let haveBacklog = false;
|
let haveBacklog = false;
|
||||||
const due = (data.cards as pb.BackendProto.Card[])
|
const due = (data.cards as Backend.Card[])
|
||||||
.filter((c: pb.BackendProto.Card) => {
|
.filter((c: Backend.Card) => {
|
||||||
// reviews
|
// reviews
|
||||||
return (
|
return (
|
||||||
[CardQueue.Review, CardQueue.DayLearn].includes(c.queue) ||
|
[CardQueue.Review, CardQueue.DayLearn].includes(c.queue) ||
|
||||||
|
@ -44,7 +44,7 @@ export function gatherData(data: pb.BackendProto.GraphsResponse): GraphData {
|
||||||
isLearning(c)
|
isLearning(c)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.map((c: pb.BackendProto.Card) => {
|
.map((c: Backend.Card) => {
|
||||||
let dueDay: number;
|
let dueDay: number;
|
||||||
|
|
||||||
if (isLearning(c)) {
|
if (isLearning(c)) {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
@typescript-eslint/no-explicit-any: "off",
|
@typescript-eslint/no-explicit-any: "off",
|
||||||
@typescript-eslint/ban-ts-comment: "off" */
|
@typescript-eslint/ban-ts-comment: "off" */
|
||||||
|
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
import type { Selection } from "d3";
|
import type { Selection } from "d3";
|
||||||
|
|
||||||
// amount of data to fetch from backend
|
// amount of data to fetch from backend
|
||||||
|
@ -28,8 +28,8 @@ export enum GraphRange {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GraphsContext {
|
export interface GraphsContext {
|
||||||
cards: pb.BackendProto.Card[];
|
cards: Backend.Card[];
|
||||||
revlog: pb.BackendProto.RevlogEntry[];
|
revlog: Backend.RevlogEntry[];
|
||||||
revlogRange: RevlogRange;
|
revlogRange: RevlogRange;
|
||||||
nightMode: boolean;
|
nightMode: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
@typescript-eslint/no-explicit-any: "off",
|
@typescript-eslint/no-explicit-any: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
import {
|
import {
|
||||||
interpolateBlues,
|
interpolateBlues,
|
||||||
select,
|
select,
|
||||||
|
@ -37,15 +37,15 @@ interface Hour {
|
||||||
correctCount: number;
|
correctCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ReviewKind = pb.BackendProto.RevlogEntry.ReviewKind;
|
const ReviewKind = Backend.RevlogEntry.ReviewKind;
|
||||||
|
|
||||||
function gatherData(data: pb.BackendProto.GraphsResponse, range: GraphRange): Hour[] {
|
function gatherData(data: Backend.GraphsResponse, range: GraphRange): Hour[] {
|
||||||
const hours = [...Array(24)].map((_n, idx: number) => {
|
const hours = [...Array(24)].map((_n, idx: number) => {
|
||||||
return { hour: idx, totalCount: 0, correctCount: 0 } as Hour;
|
return { hour: idx, totalCount: 0, correctCount: 0 } as Hour;
|
||||||
});
|
});
|
||||||
const cutoff = millisecondCutoffForRange(range, data.nextDayAtSecs);
|
const cutoff = millisecondCutoffForRange(range, data.nextDayAtSecs);
|
||||||
|
|
||||||
for (const review of data.revlog as pb.BackendProto.RevlogEntry[]) {
|
for (const review of data.revlog as Backend.RevlogEntry[]) {
|
||||||
switch (review.reviewKind) {
|
switch (review.reviewKind) {
|
||||||
case ReviewKind.LEARNING:
|
case ReviewKind.LEARNING:
|
||||||
case ReviewKind.REVIEW:
|
case ReviewKind.REVIEW:
|
||||||
|
@ -74,7 +74,7 @@ function gatherData(data: pb.BackendProto.GraphsResponse, range: GraphRange): Ho
|
||||||
export function renderHours(
|
export function renderHours(
|
||||||
svgElem: SVGElement,
|
svgElem: SVGElement,
|
||||||
bounds: GraphBounds,
|
bounds: GraphBounds,
|
||||||
origData: pb.BackendProto.GraphsResponse,
|
origData: Backend.GraphsResponse,
|
||||||
range: GraphRange
|
range: GraphRange
|
||||||
): void {
|
): void {
|
||||||
const data = gatherData(origData, range);
|
const data = gatherData(origData, range);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
@typescript-eslint/no-explicit-any: "off",
|
@typescript-eslint/no-explicit-any: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type pb from "lib/backend_proto";
|
import type { Backend } from "lib/proto";
|
||||||
import {
|
import {
|
||||||
extent,
|
extent,
|
||||||
histogram,
|
histogram,
|
||||||
|
@ -36,10 +36,8 @@ export enum IntervalRange {
|
||||||
All = 3,
|
All = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gatherIntervalData(
|
export function gatherIntervalData(data: Backend.GraphsResponse): IntervalGraphData {
|
||||||
data: pb.BackendProto.GraphsResponse
|
const intervals = (data.cards as Backend.Card[])
|
||||||
): IntervalGraphData {
|
|
||||||
const intervals = (data.cards as pb.BackendProto.Card[])
|
|
||||||
.filter((c) => [CardType.Review, CardType.Relearn].includes(c.ctype))
|
.filter((c) => [CardType.Review, CardType.Relearn].includes(c.ctype))
|
||||||
.map((c) => c.interval);
|
.map((c) => c.interval);
|
||||||
return { intervals };
|
return { intervals };
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
@typescript-eslint/no-explicit-any: "off",
|
@typescript-eslint/no-explicit-any: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
|
|
||||||
import { timeSpan, dayLabel } from "lib/time";
|
import { timeSpan, dayLabel } from "lib/time";
|
||||||
import {
|
import {
|
||||||
|
@ -50,15 +50,15 @@ export interface GraphData {
|
||||||
reviewTime: Map<number, Reviews>;
|
reviewTime: Map<number, Reviews>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ReviewKind = pb.BackendProto.RevlogEntry.ReviewKind;
|
const ReviewKind = Backend.RevlogEntry.ReviewKind;
|
||||||
type BinType = Bin<Map<number, Reviews[]>, number>;
|
type BinType = Bin<Map<number, Reviews[]>, number>;
|
||||||
|
|
||||||
export function gatherData(data: pb.BackendProto.GraphsResponse): GraphData {
|
export function gatherData(data: Backend.GraphsResponse): GraphData {
|
||||||
const reviewCount = new Map<number, Reviews>();
|
const reviewCount = new Map<number, Reviews>();
|
||||||
const reviewTime = new Map<number, Reviews>();
|
const reviewTime = new Map<number, Reviews>();
|
||||||
const empty = { mature: 0, young: 0, learn: 0, relearn: 0, early: 0 };
|
const empty = { mature: 0, young: 0, learn: 0, relearn: 0, early: 0 };
|
||||||
|
|
||||||
for (const review of data.revlog as pb.BackendProto.RevlogEntry[]) {
|
for (const review of data.revlog as Backend.RevlogEntry[]) {
|
||||||
if (review.reviewKind == ReviewKind.MANUAL) {
|
if (review.reviewKind == ReviewKind.MANUAL) {
|
||||||
// don't count days with only manual scheduling
|
// don't count days with only manual scheduling
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
import pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
import { studiedToday } from "lib/time";
|
import { studiedToday } from "lib/time";
|
||||||
|
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
|
@ -11,9 +11,9 @@ export interface TodayData {
|
||||||
lines: string[];
|
lines: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const ReviewKind = pb.BackendProto.RevlogEntry.ReviewKind;
|
const ReviewKind = Backend.RevlogEntry.ReviewKind;
|
||||||
|
|
||||||
export function gatherData(data: pb.BackendProto.GraphsResponse): TodayData {
|
export function gatherData(data: Backend.GraphsResponse): TodayData {
|
||||||
let answerCount = 0;
|
let answerCount = 0;
|
||||||
let answerMillis = 0;
|
let answerMillis = 0;
|
||||||
let correctCount = 0;
|
let correctCount = 0;
|
||||||
|
@ -26,7 +26,7 @@ export function gatherData(data: pb.BackendProto.GraphsResponse): TodayData {
|
||||||
|
|
||||||
const startOfTodayMillis = (data.nextDayAtSecs - 86400) * 1000;
|
const startOfTodayMillis = (data.nextDayAtSecs - 86400) * 1000;
|
||||||
|
|
||||||
for (const review of data.revlog as pb.BackendProto.RevlogEntry[]) {
|
for (const review of data.revlog as Backend.RevlogEntry[]) {
|
||||||
if (review.id < startOfTodayMillis) {
|
if (review.id < startOfTodayMillis) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
6
ts/lib/proto.ts
Normal file
6
ts/lib/proto.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
|
import { anki } from "./backend_proto";
|
||||||
|
import Backend = anki.backend;
|
||||||
|
export { Backend };
|
|
@ -8,10 +8,7 @@ load("//ts:compile_sass.bzl", "compile_sass")
|
||||||
ts_library(
|
ts_library(
|
||||||
name = "lib",
|
name = "lib",
|
||||||
srcs = glob(["*.ts"]),
|
srcs = glob(["*.ts"]),
|
||||||
deps = [
|
deps = ["//ts/lib"],
|
||||||
"//ts/lib",
|
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
esbuild(
|
esbuild(
|
||||||
|
@ -25,7 +22,6 @@ esbuild(
|
||||||
deps = [
|
deps = [
|
||||||
":lib",
|
":lib",
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
"@npm//protobufjs",
|
"@npm//protobufjs",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
import * as pb from "lib/backend_proto";
|
import { Backend } from "lib/proto";
|
||||||
import { postRequest } from "lib/postrequest";
|
import { postRequest } from "lib/postrequest";
|
||||||
|
|
||||||
async function getNextStates(): Promise<pb.BackendProto.NextCardStates> {
|
async function getNextStates(): Promise<Backend.NextCardStates> {
|
||||||
return pb.BackendProto.NextCardStates.decode(
|
return Backend.NextCardStates.decode(
|
||||||
await postRequest("/_anki/nextCardStates", "")
|
await postRequest("/_anki/nextCardStates", "")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setNextStates(
|
async function setNextStates(
|
||||||
key: string,
|
key: string,
|
||||||
states: pb.BackendProto.NextCardStates
|
states: Backend.NextCardStates
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const data: Uint8Array = pb.BackendProto.NextCardStates.encode(states).finish();
|
const data: Uint8Array = Backend.NextCardStates.encode(states).finish();
|
||||||
await postRequest("/_anki/setNextCardStates", data, { key });
|
await postRequest("/_anki/setNextCardStates", data, { key });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function mutateNextCardStates(
|
export async function mutateNextCardStates(
|
||||||
key: string,
|
key: string,
|
||||||
mutator: (states: pb.BackendProto.NextCardStates) => void
|
mutator: (states: Backend.NextCardStates) => void
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const states = await getNextStates();
|
const states = await getNextStates();
|
||||||
mutator(states);
|
mutator(states);
|
||||||
|
|
|
@ -91,7 +91,6 @@ def svelte_check(name = "svelte_check", srcs = []):
|
||||||
"//ts:tsconfig.json",
|
"//ts:tsconfig.json",
|
||||||
"//ts/sveltelib",
|
"//ts/sveltelib",
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/lib:backend_proto",
|
|
||||||
"@npm//sass",
|
"@npm//sass",
|
||||||
] + srcs,
|
] + srcs,
|
||||||
env = {"SASS_PATH": "$(rootpath //ts:tsconfig.json)/../.."},
|
env = {"SASS_PATH": "$(rootpath //ts:tsconfig.json)/../.."},
|
||||||
|
|
|
@ -157,9 +157,9 @@ async function writeJs(
|
||||||
genDir,
|
genDir,
|
||||||
// a nasty hack to ensure ts/sass/... resolves correctly
|
// a nasty hack to ensure ts/sass/... resolves correctly
|
||||||
// when invoked from an external workspace
|
// when invoked from an external workspace
|
||||||
binDir + "/external/net_ankiweb_anki",
|
binDir + "/external/anki",
|
||||||
genDir + "/external/net_ankiweb_anki",
|
genDir + "/external/anki",
|
||||||
binDir + "/../../../external/net_ankiweb_anki",
|
binDir + "/../../../external/anki",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue