add schema change prompt to removal, tweak return struct
This commit is contained in:
parent
55e1176653
commit
76eb119870
@ -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
|
||||
|
@ -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."
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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<pb::DeckConfigForUpdate> {
|
||||
self.with_col(|col| col.get_deck_config_for_update(input.into()))
|
||||
fn get_deck_configs_for_update(&self, input: pb::DeckId) -> Result<pb::DeckConfigsForUpdate> {
|
||||
self.with_col(|col| col.get_deck_configs_for_update(input.into()))
|
||||
}
|
||||
|
||||
fn update_deck_config(&self, _input: pb::UpdateDeckConfigIn) -> Result<pb::OpChanges> {
|
||||
todo!();
|
||||
fn update_deck_configs(&self, input: pb::UpdateDeckConfigsIn) -> Result<pb::OpChanges> {
|
||||
self.with_col(|col| col.update_deck_configs(input.into()))
|
||||
.map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,3 +83,26 @@ impl From<DeckConf> for pb::DeckConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pb::UpdateDeckConfigsIn> 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<pb::DeckConfig> 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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<DeckConf>,
|
||||
pub removed_config_ids: Vec<DeckId>,
|
||||
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<pb::DeckConfigForUpdate> {
|
||||
Ok(pb::DeckConfigForUpdate {
|
||||
pub fn get_deck_configs_for_update(
|
||||
&mut self,
|
||||
deck: DeckId,
|
||||
) -> Result<pb::DeckConfigsForUpdate> {
|
||||
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<OpOutput<()>> {
|
||||
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!();
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -297,6 +297,13 @@ impl SqliteStorage {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn schema_modified(&self) -> Result<bool> {
|
||||
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<TimestampMillis> {
|
||||
self.db
|
||||
.prepare_cached("select scm from col")?
|
||||
|
@ -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));
|
||||
}
|
||||
</script>
|
||||
@ -60,7 +60,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
<div>{tr.actionsOptionsFor({ val: state.currentDeck.name })}</div>
|
||||
|
||||
<!-- svelte-ignore a11y-no-onchange -->
|
||||
<select class="form-select" on:change={myblur}>
|
||||
<select class="form-select" on:change={blur}>
|
||||
{#each $configList as entry}
|
||||
<option value={entry.idx} selected={entry.current}>
|
||||
{configLabel(entry)}
|
||||
|
@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
-->
|
||||
<script lang="ts">
|
||||
// import * as tr from "anki/i18n";
|
||||
import * as tr from "anki/i18n";
|
||||
import { textInputModal } from "./textInputModal";
|
||||
import type { DeckConfigState } from "./lib";
|
||||
|
||||
@ -34,8 +34,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
}
|
||||
|
||||
function removeConfig(): void {
|
||||
// show pop-up after dropdown has gone away
|
||||
setTimeout(() => {
|
||||
if (confirm("Are you sure?")) {
|
||||
if (state.defaultConfigSelected()) {
|
||||
alert(tr.schedulingTheDefaultConfigurationCantBeRemoved());
|
||||
return;
|
||||
}
|
||||
// fixme: move tr.qt_misc schema mod msg into core
|
||||
// fixme: include name of deck in msg
|
||||
const msg = state.removalWilLForceFullSync()
|
||||
? "This will require a one-way sync. Are you sure?"
|
||||
: "Are you sure?";
|
||||
if (confirm(msg)) {
|
||||
try {
|
||||
state.removeCurrentConfig();
|
||||
} catch (err) {
|
||||
|
@ -92,7 +92,7 @@ const exampleData = {
|
||||
|
||||
function startingState(): DeckConfigState {
|
||||
return new DeckConfigState(
|
||||
pb.BackendProto.DeckConfigForUpdate.fromObject(exampleData)
|
||||
pb.BackendProto.DeckConfigsForUpdate.fromObject(exampleData)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -13,9 +13,9 @@ import * as tr from "anki/i18n";
|
||||
|
||||
export async function getDeckConfigInfo(
|
||||
deckId: number
|
||||
): Promise<pb.BackendProto.DeckConfigForUpdate> {
|
||||
return pb.BackendProto.DeckConfigForUpdate.decode(
|
||||
await postRequest("/_anki/deckConfigForUpdate", JSON.stringify({ deckId }))
|
||||
): Promise<pb.BackendProto.DeckConfigsForUpdate> {
|
||||
return pb.BackendProto.DeckConfigsForUpdate.decode(
|
||||
await postRequest("/_anki/deckConfigsForUpdate", JSON.stringify({ deckId }))
|
||||
);
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ export class DeckConfigState {
|
||||
readonly currentConfig: Writable<ConfigInner>;
|
||||
readonly configList: Readable<ConfigListEntry[]>;
|
||||
readonly parentLimits: Readable<ParentLimits>;
|
||||
readonly currentDeck: pb.BackendProto.DeckConfigForUpdate.CurrentDeck;
|
||||
readonly currentDeck: pb.BackendProto.DeckConfigsForUpdate.CurrentDeck;
|
||||
readonly defaults: ConfigInner;
|
||||
|
||||
private configs: ConfigWithCount[];
|
||||
@ -52,9 +52,10 @@ export class DeckConfigState {
|
||||
private configListSetter!: (val: ConfigListEntry[]) => void;
|
||||
private parentLimitsSetter!: (val: ParentLimits) => void;
|
||||
private removedConfigs: DeckConfigId[] = [];
|
||||
private schemaModified: boolean;
|
||||
|
||||
constructor(data: pb.BackendProto.DeckConfigForUpdate) {
|
||||
this.currentDeck = data.currentDeck as pb.BackendProto.DeckConfigForUpdate.CurrentDeck;
|
||||
constructor(data: pb.BackendProto.DeckConfigsForUpdate) {
|
||||
this.currentDeck = data.currentDeck as pb.BackendProto.DeckConfigsForUpdate.CurrentDeck;
|
||||
this.defaults = data.defaults!.config! as ConfigInner;
|
||||
this.configs = data.allConfig.map((config) => {
|
||||
return {
|
||||
@ -79,6 +80,7 @@ export class DeckConfigState {
|
||||
this.parentLimitsSetter = set;
|
||||
return;
|
||||
});
|
||||
this.schemaModified = data.schemaModified;
|
||||
|
||||
// create a temporary subscription to force our setters to be set immediately,
|
||||
// so unit tests don't get stale results
|
||||
@ -126,6 +128,14 @@ export class DeckConfigState {
|
||||
this.updateConfigList();
|
||||
}
|
||||
|
||||
removalWilLForceFullSync(): boolean {
|
||||
return !this.schemaModified && this.configs[this.selectedIdx].config.id !== 0;
|
||||
}
|
||||
|
||||
defaultConfigSelected(): boolean {
|
||||
return this.configs[this.selectedIdx].config.id === 1;
|
||||
}
|
||||
|
||||
/// Will throw if the default deck is selected.
|
||||
removeCurrentConfig(): void {
|
||||
const currentId = this.configs[this.selectedIdx].config.id;
|
||||
@ -135,6 +145,7 @@ export class DeckConfigState {
|
||||
|
||||
if (currentId !== 0) {
|
||||
this.removedConfigs.push(currentId);
|
||||
this.schemaModified = true;
|
||||
}
|
||||
this.configs.splice(this.selectedIdx, 1);
|
||||
this.selectedIdx = Math.max(0, this.selectedIdx - 1);
|
||||
|
Loading…
Reference in New Issue
Block a user