From 76eb1198708e181c95d5f9b02de7aca59c684a70 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sun, 18 Apr 2021 11:56:41 +1000 Subject: [PATCH] add schema change prompt to removal, tweak return struct --- ftl/core/undo.ftl | 1 + pylib/anki/decks.py | 6 ++--- qt/aqt/mediasrv.py | 6 ++--- rslib/backend.proto | 19 +++++++++------- rslib/src/backend/deckconfig.rs | 34 ++++++++++++++++++++++++---- rslib/src/deckconf/mod.rs | 20 +++++++++------- rslib/src/deckconf/update.rs | 33 ++++++++++++++++++++++++--- rslib/src/ops.rs | 2 ++ rslib/src/storage/sqlite.rs | 7 ++++++ ts/deckconfig/ConfigSelector.svelte | 4 ++-- ts/deckconfig/OptionsDropdown.svelte | 14 ++++++++++-- ts/deckconfig/lib.test.ts | 2 +- ts/deckconfig/lib.ts | 23 ++++++++++++++----- 13 files changed, 130 insertions(+), 41 deletions(-) diff --git a/ftl/core/undo.ftl b/ftl/core/undo.ftl index f3e32ccaa..cb386b4b0 100644 --- a/ftl/core/undo.ftl +++ b/ftl/core/undo.ftl @@ -24,3 +24,4 @@ undo-forget-card = Forget Card undo-set-flag = Set Flag undo-build-filtered-deck = Build Deck undo-expand-collapse = Expand/Collapse +undo-deck-config = Study Options diff --git a/pylib/anki/decks.py b/pylib/anki/decks.py index 022c3f27a..cc5d81bf4 100644 --- a/pylib/anki/decks.py +++ b/pylib/anki/decks.py @@ -22,7 +22,7 @@ DeckTreeNode = _pb.DeckTreeNode DeckNameId = _pb.DeckNameId FilteredDeckConfig = _pb.Deck.Filtered DeckCollapseScope = _pb.SetDeckCollapsedIn.Scope -DeckConfigForUpdate = _pb.DeckConfigForUpdate +DeckConfigsForUpdate = _pb.DeckConfigsForUpdate # legacy code may pass this in as the type argument to .id() defaultDeck = 0 @@ -325,8 +325,8 @@ class DeckManager: # Deck configurations ############################################################# - def get_deck_config_for_update(self, deck_id: DeckId) -> DeckConfigForUpdate: - return self.col._backend.get_deck_config_for_update(deck_id) + def get_deck_configs_for_update(self, deck_id: DeckId) -> DeckConfigsForUpdate: + return self.col._backend.get_deck_configs_for_update(deck_id) def all_config(self) -> List[DeckConfigDict]: "A list of all deck config." diff --git a/qt/aqt/mediasrv.py b/qt/aqt/mediasrv.py index 6df56f0d8..9d7f8f7e7 100644 --- a/qt/aqt/mediasrv.py +++ b/qt/aqt/mediasrv.py @@ -276,9 +276,9 @@ def i18n_resources() -> bytes: return aqt.mw.col.i18n_resources(modules=args["modules"]) -def deck_config_for_update() -> bytes: +def deck_configs_for_update() -> bytes: args = from_json_bytes(request.data) - return aqt.mw.col.decks.get_deck_config_for_update( + return aqt.mw.col.decks.get_deck_configs_for_update( deck_id=args["deckId"] ).SerializeToString() @@ -287,7 +287,7 @@ post_handlers = { "graphData": graph_data, "graphPreferences": graph_preferences, "setGraphPreferences": set_graph_preferences, - "deckConfigForUpdate": deck_config_for_update, + "deckConfigsForUpdate": deck_configs_for_update, # pylint: disable=unnecessary-lambda "i18nResources": i18n_resources, "congratsInfo": congrats_info, diff --git a/rslib/backend.proto b/rslib/backend.proto index e58d5b70e..85603fbe6 100644 --- a/rslib/backend.proto +++ b/rslib/backend.proto @@ -228,8 +228,8 @@ service DeckConfigService { rpc GetDeckConfigLegacy(DeckConfigId) returns (Json); rpc NewDeckConfigLegacy(Empty) returns (Json); rpc RemoveDeckConfig(DeckConfigId) returns (Empty); - rpc GetDeckConfigForUpdate(DeckId) returns (DeckConfigForUpdate); - rpc UpdateDeckConfig(UpdateDeckConfigIn) returns (OpChanges); + rpc GetDeckConfigsForUpdate(DeckId) returns (DeckConfigsForUpdate); + rpc UpdateDeckConfigs(UpdateDeckConfigsIn) returns (OpChanges); } service TagsService { @@ -895,7 +895,7 @@ message AddOrUpdateDeckConfigLegacyIn { bool preserve_usn_and_mtime = 2; } -message DeckConfigForUpdate { +message DeckConfigsForUpdate { message ConfigWithExtra { DeckConfig config = 1; uint32 use_count = 2; @@ -909,13 +909,16 @@ message DeckConfigForUpdate { repeated ConfigWithExtra all_config = 1; CurrentDeck current_deck = 2; DeckConfig defaults = 3; + bool schema_modified = 4; } -message UpdateDeckConfigIn { - int64 target_deck_id = 2; - DeckConfig desired_config = 3; - repeated int64 removed_config_ids = 4; - bool apply_to_children = 5; +message UpdateDeckConfigsIn { + int64 target_deck_id = 1; + /// Unchanged, non-selected configs can be omitted. Deck will + /// be set to whichever entry comes last. + repeated DeckConfig configs = 2; + repeated int64 removed_config_ids = 3; + bool apply_to_children = 4; } message SetTagCollapsedIn { diff --git a/rslib/src/backend/deckconfig.rs b/rslib/src/backend/deckconfig.rs index 53ce9c1a9..86b813dca 100644 --- a/rslib/src/backend/deckconfig.rs +++ b/rslib/src/backend/deckconfig.rs @@ -4,7 +4,7 @@ use super::Backend; use crate::{ backend_proto as pb, - deckconf::{DeckConf, DeckConfSchema11}, + deckconf::{DeckConf, DeckConfSchema11, UpdateDeckConfigsIn}, prelude::*, }; pub(super) use pb::deckconfig_service::Service as DeckConfigService; @@ -62,12 +62,13 @@ impl DeckConfigService for Backend { .map(Into::into) } - fn get_deck_config_for_update(&self, input: pb::DeckId) -> Result { - self.with_col(|col| col.get_deck_config_for_update(input.into())) + fn get_deck_configs_for_update(&self, input: pb::DeckId) -> Result { + self.with_col(|col| col.get_deck_configs_for_update(input.into())) } - fn update_deck_config(&self, _input: pb::UpdateDeckConfigIn) -> Result { - todo!(); + fn update_deck_configs(&self, input: pb::UpdateDeckConfigsIn) -> Result { + self.with_col(|col| col.update_deck_configs(input.into())) + .map(Into::into) } } @@ -82,3 +83,26 @@ impl From for pb::DeckConfig { } } } + +impl From for UpdateDeckConfigsIn { + fn from(c: pb::UpdateDeckConfigsIn) -> Self { + UpdateDeckConfigsIn { + target_deck_id: c.target_deck_id.into(), + configs: c.configs.into_iter().map(Into::into).collect(), + removed_config_ids: c.removed_config_ids.into_iter().map(Into::into).collect(), + apply_to_children: c.apply_to_children, + } + } +} + +impl From for DeckConf { + fn from(c: pb::DeckConfig) -> Self { + DeckConf { + id: c.id.into(), + name: c.name, + mtime_secs: c.mtime_secs.into(), + usn: c.usn.into(), + inner: c.config.unwrap_or_default(), + } + } +} diff --git a/rslib/src/deckconf/mod.rs b/rslib/src/deckconf/mod.rs index d7d0675d5..c28878526 100644 --- a/rslib/src/deckconf/mod.rs +++ b/rslib/src/deckconf/mod.rs @@ -4,6 +4,18 @@ mod schema11; mod update; +pub use { + crate::backend_proto::{ + deck_config::config::{LeechAction, NewCardOrder, ReviewCardOrder, ReviewMix}, + deck_config::Config as DeckConfigInner, + }, + schema11::{DeckConfSchema11, NewCardOrderSchema11}, + update::UpdateDeckConfigsIn, +}; + +/// Old deck config and cards table store 250% as 2500. +pub(crate) const INITIAL_EASE_FACTOR_THOUSANDS: u16 = (INITIAL_EASE_FACTOR * 1000.0) as u16; + use crate::{ collection::Collection, define_newtype, @@ -13,14 +25,6 @@ use crate::{ types::Usn, }; -pub use crate::backend_proto::{ - deck_config::config::{LeechAction, NewCardOrder, ReviewCardOrder, ReviewMix}, - deck_config::Config as DeckConfigInner, -}; -pub use schema11::{DeckConfSchema11, NewCardOrderSchema11}; -/// Old deck config and cards table store 250% as 2500. -pub(crate) const INITIAL_EASE_FACTOR_THOUSANDS: u16 = (INITIAL_EASE_FACTOR * 1000.0) as u16; - define_newtype!(DeckConfId, i64); #[derive(Debug, PartialEq, Clone)] diff --git a/rslib/src/deckconf/update.rs b/rslib/src/deckconf/update.rs index 98ed1c6a0..82959fc6f 100644 --- a/rslib/src/deckconf/update.rs +++ b/rslib/src/deckconf/update.rs @@ -3,17 +3,36 @@ use std::collections::{HashMap, HashSet}; -use pb::deck_config_for_update::{ConfigWithExtra, CurrentDeck}; +use pb::deck_configs_for_update::{ConfigWithExtra, CurrentDeck}; use crate::{backend_proto as pb, prelude::*}; +pub struct UpdateDeckConfigsIn { + pub target_deck_id: DeckId, + /// Deck will be set to last provided deck config. + pub configs: Vec, + pub removed_config_ids: Vec, + pub apply_to_children: bool, +} + impl Collection { /// Information required for the deck options screen. - pub fn get_deck_config_for_update(&mut self, deck: DeckId) -> Result { - Ok(pb::DeckConfigForUpdate { + pub fn get_deck_configs_for_update( + &mut self, + deck: DeckId, + ) -> Result { + Ok(pb::DeckConfigsForUpdate { all_config: self.get_deck_config_with_extra_for_update()?, current_deck: Some(self.get_current_deck_for_update(deck)?), defaults: Some(DeckConf::default().into()), + schema_modified: self.storage.schema_modified()?, + }) + } + + /// Information required for the deck options screen. + pub fn update_deck_configs(&mut self, input: UpdateDeckConfigsIn) -> Result> { + self.transact(Op::UpdateDeckConfig, |col| { + col.update_deck_configs_inner(input) }) } } @@ -73,4 +92,12 @@ impl Collection { }) .collect()) } + + fn update_deck_configs_inner(&mut self, input: UpdateDeckConfigsIn) -> Result<()> { + if input.configs.is_empty() { + return Err(AnkiError::invalid_input("config not provided")); + } + + todo!(); + } } diff --git a/rslib/src/ops.rs b/rslib/src/ops.rs index 47c2848bb..aecd68507 100644 --- a/rslib/src/ops.rs +++ b/rslib/src/ops.rs @@ -31,6 +31,7 @@ pub enum Op { UnburyUnsuspend, UpdateCard, UpdateDeck, + UpdateDeckConfig, UpdateNote, UpdatePreferences, UpdateTag, @@ -70,6 +71,7 @@ impl Op { Op::EmptyFilteredDeck => tr.studying_empty(), Op::ExpandCollapse => tr.undo_expand_collapse(), Op::SetCurrentDeck => tr.browsing_change_deck(), + Op::UpdateDeckConfig => tr.undo_deck_config(), } .into() } diff --git a/rslib/src/storage/sqlite.rs b/rslib/src/storage/sqlite.rs index cbfe67c26..967d5c974 100644 --- a/rslib/src/storage/sqlite.rs +++ b/rslib/src/storage/sqlite.rs @@ -297,6 +297,13 @@ impl SqliteStorage { Ok(()) } + pub(crate) fn schema_modified(&self) -> Result { + self.db + .prepare_cached("select scm > ls from col")? + .query_row(NO_PARAMS, |r| r.get(0)) + .map_err(Into::into) + } + pub(crate) fn get_schema_mtime(&self) -> Result { self.db .prepare_cached("select scm from col")? diff --git a/ts/deckconfig/ConfigSelector.svelte b/ts/deckconfig/ConfigSelector.svelte index bd10849a0..138f62b6e 100644 --- a/ts/deckconfig/ConfigSelector.svelte +++ b/ts/deckconfig/ConfigSelector.svelte @@ -15,7 +15,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html return `${entry.name} (${count})`; } - function myblur(this: HTMLSelectElement) { + function blur(this: HTMLSelectElement) { state.setCurrentIndex(parseInt(this.value)); } @@ -60,7 +60,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{tr.actionsOptionsFor({ val: state.currentDeck.name })}
- {#each $configList as entry}