implement deck config updating
This commit is contained in:
parent
4d4603c078
commit
4d1cedc8b2
@ -58,7 +58,7 @@ impl DeckConfigService for Backend {
|
||||
}
|
||||
|
||||
fn remove_deck_config(&self, input: pb::DeckConfigId) -> Result<pb::Empty> {
|
||||
self.with_col(|col| col.transact_no_undo(|col| col.remove_deck_config(input.into())))
|
||||
self.with_col(|col| col.transact_no_undo(|col| col.remove_deck_config_inner(input.into())))
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,13 @@ impl Default for DeckConf {
|
||||
}
|
||||
}
|
||||
|
||||
impl DeckConf {
|
||||
pub(crate) fn set_modified(&mut self, usn: Usn) {
|
||||
self.mtime_secs = TimestampSecs::now();
|
||||
self.usn = usn;
|
||||
}
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
/// If fallback is true, guaranteed to return a deck config.
|
||||
pub fn get_deck_config(&self, dcid: DeckConfId, fallback: bool) -> Result<Option<DeckConf>> {
|
||||
@ -92,29 +99,64 @@ impl Collection {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
pub(crate) fn add_or_update_deck_config(
|
||||
&self,
|
||||
conf: &mut DeckConf,
|
||||
&mut self,
|
||||
config: &mut DeckConf,
|
||||
preserve_usn_and_mtime: bool,
|
||||
) -> Result<()> {
|
||||
if !preserve_usn_and_mtime {
|
||||
conf.mtime_secs = TimestampSecs::now();
|
||||
conf.usn = self.usn()?;
|
||||
}
|
||||
let orig = self.storage.get_deck_config(conf.id)?;
|
||||
if let Some(_orig) = orig {
|
||||
self.storage.update_deck_conf(&conf)
|
||||
let usn = if preserve_usn_and_mtime {
|
||||
None
|
||||
} else {
|
||||
if conf.id.0 == 0 {
|
||||
conf.id.0 = TimestampMillis::now().0;
|
||||
}
|
||||
self.storage.add_deck_conf(conf)
|
||||
Some(self.usn()?)
|
||||
};
|
||||
|
||||
if config.id.0 == 0 {
|
||||
self.add_deck_config_inner(config, usn)
|
||||
} else {
|
||||
let original = self
|
||||
.storage
|
||||
.get_deck_config(config.id)?
|
||||
.ok_or(AnkiError::NotFound)?;
|
||||
self.update_deck_config_inner(config, original, usn)
|
||||
}
|
||||
}
|
||||
|
||||
/// Assigns an id and adds to DB. If usn is provided, modification time and
|
||||
/// usn will be updated.
|
||||
pub(crate) fn add_deck_config_inner(
|
||||
&mut self,
|
||||
config: &mut DeckConf,
|
||||
usn: Option<Usn>,
|
||||
) -> Result<()> {
|
||||
if let Some(usn) = usn {
|
||||
config.set_modified(usn);
|
||||
}
|
||||
config.id.0 = TimestampMillis::now().0;
|
||||
self.add_deck_config_undoable(config)
|
||||
}
|
||||
|
||||
/// Update an existing deck config. If usn is provided, modification time
|
||||
/// and usn will be updated.
|
||||
pub(crate) fn update_deck_config_inner(
|
||||
&mut self,
|
||||
config: &mut DeckConf,
|
||||
original: DeckConf,
|
||||
usn: Option<Usn>,
|
||||
) -> Result<()> {
|
||||
if config == &original {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(usn) = usn {
|
||||
config.set_modified(usn);
|
||||
}
|
||||
self.update_deck_config_undoable(config, original)
|
||||
}
|
||||
|
||||
/// Remove a deck configuration. This will force a full sync.
|
||||
pub(crate) fn remove_deck_config(&mut self, dcid: DeckConfId) -> Result<()> {
|
||||
pub(crate) fn remove_deck_config_inner(&mut self, dcid: DeckConfId) -> Result<()> {
|
||||
if dcid.0 == 1 {
|
||||
return Err(AnkiError::invalid_input("can't delete default conf"));
|
||||
}
|
||||
|
@ -11,8 +11,6 @@ pub(crate) enum UndoableDeckConfigChange {
|
||||
Removed(Box<DeckConf>),
|
||||
}
|
||||
|
||||
// fixme: schema mod
|
||||
|
||||
impl Collection {
|
||||
pub(crate) fn undo_deck_config_change(
|
||||
&mut self,
|
||||
@ -20,12 +18,12 @@ impl Collection {
|
||||
) -> Result<()> {
|
||||
match change {
|
||||
UndoableDeckConfigChange::Added(config) => self.remove_deck_config_undoable(*config),
|
||||
UndoableDeckConfigChange::Updated(mut config) => {
|
||||
UndoableDeckConfigChange::Updated(config) => {
|
||||
let current = self
|
||||
.storage
|
||||
.get_deck_config(config.id)?
|
||||
.ok_or_else(|| AnkiError::invalid_input("deck config disappeared"))?;
|
||||
self.update_single_deck_config_undoable(&mut *config, current)
|
||||
self.update_deck_config_undoable(&config, current)
|
||||
}
|
||||
UndoableDeckConfigChange::Removed(config) => self.restore_deleted_deck_config(*config),
|
||||
}
|
||||
@ -37,7 +35,6 @@ impl Collection {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(super) fn add_deck_config_undoable(
|
||||
&mut self,
|
||||
config: &mut DeckConf,
|
||||
@ -47,26 +44,15 @@ impl Collection {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn update_single_deck_config_undoable(
|
||||
pub(super) fn update_deck_config_undoable(
|
||||
&mut self,
|
||||
config: &mut DeckConf,
|
||||
config: &DeckConf,
|
||||
original: DeckConf,
|
||||
) -> Result<()> {
|
||||
self.save_undo(UndoableDeckConfigChange::Updated(Box::new(original)));
|
||||
self.storage.update_deck_conf(config)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn add_or_update_deck_config_with_existing_id_undoable(
|
||||
&mut self,
|
||||
config: &mut DeckConf,
|
||||
) -> Result<(), AnkiError> {
|
||||
self.storage
|
||||
.add_or_update_deck_config_with_existing_id(config)?;
|
||||
self.save_undo(UndoableDeckConfigChange::Added(Box::new(config.clone())));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn restore_deleted_deck_config(&mut self, config: DeckConf) -> Result<()> {
|
||||
self.storage
|
||||
.add_or_update_deck_config_with_existing_id(&config)?;
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
//! Updating configs in bulk, from the deck config screen.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::{
|
||||
@ -98,15 +100,42 @@ impl Collection {
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn update_deck_configs_inner(&mut self, input: UpdateDeckConfigsIn) -> Result<()> {
|
||||
fn update_deck_configs_inner(&mut self, mut input: UpdateDeckConfigsIn) -> Result<()> {
|
||||
if input.configs.is_empty() {
|
||||
return Err(AnkiError::invalid_input("config not provided"));
|
||||
}
|
||||
|
||||
// handle removals first
|
||||
for dcid in &input.removed_config_ids {
|
||||
self.remove_deck_config(*dcid)?;
|
||||
self.remove_deck_config_inner(*dcid)?;
|
||||
}
|
||||
|
||||
todo!();
|
||||
// add/update provided configs
|
||||
for conf in &mut input.configs {
|
||||
self.add_or_update_deck_config(conf, false)?;
|
||||
}
|
||||
|
||||
// point current deck to last config
|
||||
let usn = self.usn()?;
|
||||
let config_id = input.configs.last().unwrap().id;
|
||||
let mut deck = self
|
||||
.storage
|
||||
.get_deck(input.target_deck_id)?
|
||||
.ok_or(AnkiError::NotFound)?;
|
||||
let original = deck.clone();
|
||||
deck.normal_mut()?.config_id = config_id.0;
|
||||
self.update_deck_inner(&mut deck, original, usn)?;
|
||||
|
||||
if input.apply_to_children {
|
||||
for mut child_deck in self.storage.child_decks(&deck)? {
|
||||
let child_original = child_deck.clone();
|
||||
if let Ok(normal) = child_deck.normal_mut() {
|
||||
normal.config_id = config_id.0;
|
||||
self.update_deck_inner(&mut child_deck, child_original, usn)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,37 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
//! Adding and updating.
|
||||
|
||||
use super::name::immediate_parent_name;
|
||||
use crate::{error::FilteredDeckError, prelude::*};
|
||||
|
||||
impl Collection {
|
||||
/// Add a new deck. The id must be 0, as it will be automatically assigned.
|
||||
pub fn add_deck(&mut self, deck: &mut Deck) -> Result<OpOutput<()>> {
|
||||
self.transact(Op::AddDeck, |col| col.add_deck_inner(deck, col.usn()?))
|
||||
}
|
||||
|
||||
pub fn update_deck(&mut self, deck: &mut Deck) -> Result<OpOutput<()>> {
|
||||
self.transact(Op::UpdateDeck, |col| {
|
||||
let existing_deck = col.storage.get_deck(deck.id)?.ok_or(AnkiError::NotFound)?;
|
||||
col.update_deck_inner(deck, existing_deck, col.usn()?)
|
||||
})
|
||||
}
|
||||
|
||||
/// Add or update an existing deck modified by the user. May add parents,
|
||||
/// or rename children as required. Prefer add_deck() or update_deck() to
|
||||
/// be explicit about your intentions; this function mainly exists so we
|
||||
/// can integrate with older Python code that behaved this way.
|
||||
pub fn add_or_update_deck(&mut self, deck: &mut Deck) -> Result<OpOutput<()>> {
|
||||
if deck.id.0 == 0 {
|
||||
self.add_deck(deck)
|
||||
} else {
|
||||
self.update_deck(deck)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
/// Rename deck if not unique. Bumps mtime and usn if
|
||||
/// name was changed, but otherwise leaves it the same.
|
||||
@ -13,41 +42,16 @@ impl Collection {
|
||||
self.ensure_deck_name_unique(deck, usn)
|
||||
}
|
||||
|
||||
/// Add or update an existing deck modified by the user. May add parents,
|
||||
/// or rename children as required. Prefer add_deck() or update_deck() to
|
||||
/// be explicit about your intentions; this function mainly exists so we
|
||||
/// can integrate with older Python code that behaved this way.
|
||||
pub(crate) fn add_or_update_deck(&mut self, deck: &mut Deck) -> Result<OpOutput<()>> {
|
||||
if deck.id.0 == 0 {
|
||||
self.add_deck(deck)
|
||||
} else {
|
||||
self.update_deck(deck)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a new deck. The id must be 0, as it will be automatically assigned.
|
||||
pub fn add_deck(&mut self, deck: &mut Deck) -> Result<OpOutput<()>> {
|
||||
pub(crate) fn add_deck_inner(&mut self, deck: &mut Deck, usn: Usn) -> Result<()> {
|
||||
if deck.id.0 != 0 {
|
||||
return Err(AnkiError::invalid_input("deck to add must have id 0"));
|
||||
}
|
||||
|
||||
self.transact(Op::AddDeck, |col| col.add_deck_inner(deck, col.usn()?))
|
||||
}
|
||||
|
||||
pub(crate) fn add_deck_inner(&mut self, deck: &mut Deck, usn: Usn) -> Result<()> {
|
||||
self.prepare_deck_for_update(deck, usn)?;
|
||||
deck.set_modified(usn);
|
||||
self.match_or_create_parents(deck, usn)?;
|
||||
self.add_deck_undoable(deck)
|
||||
}
|
||||
|
||||
pub fn update_deck(&mut self, deck: &mut Deck) -> Result<OpOutput<()>> {
|
||||
self.transact(Op::UpdateDeck, |col| {
|
||||
let existing_deck = col.storage.get_deck(deck.id)?.ok_or(AnkiError::NotFound)?;
|
||||
col.update_deck_inner(deck, existing_deck, col.usn()?)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn update_deck_inner(
|
||||
&mut self,
|
||||
deck: &mut Deck,
|
||||
@ -91,9 +95,7 @@ impl Collection {
|
||||
deck.set_modified(usn);
|
||||
self.add_or_update_single_deck_with_existing_id(&mut deck, usn)
|
||||
}
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
/// Add a single, normal deck with the provided name for a child deck.
|
||||
/// Caller must have done necessarily validation on name.
|
||||
fn add_parent_deck(&mut self, machine_name: &str, usn: Usn) -> Result<()> {
|
@ -1,7 +1,7 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
mod add;
|
||||
mod addupdate;
|
||||
mod counts;
|
||||
mod current;
|
||||
mod filtered;
|
||||
@ -134,6 +134,20 @@ impl Deck {
|
||||
}
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
pub fn get_or_create_normal_deck(&mut self, human_name: &str) -> Result<Deck> {
|
||||
let name = NativeDeckName::from_human_name(human_name);
|
||||
if let Some(did) = self.storage.get_deck_id(name.as_native_str())? {
|
||||
self.storage.get_deck(did).map(|opt| opt.unwrap())
|
||||
} else {
|
||||
let mut deck = Deck::new_normal();
|
||||
deck.name = name;
|
||||
self.add_or_update_deck(&mut deck)?;
|
||||
Ok(deck)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
pub(crate) fn get_deck(&mut self, did: DeckId) -> Result<Option<Arc<Deck>>> {
|
||||
if let Some(deck) = self.state.deck_cache.get(&did) {
|
||||
@ -152,18 +166,6 @@ impl Collection {
|
||||
self.storage.deck_is_empty(DeckId(1))
|
||||
}
|
||||
|
||||
pub fn get_or_create_normal_deck(&mut self, human_name: &str) -> Result<Deck> {
|
||||
let name = NativeDeckName::from_human_name(human_name);
|
||||
if let Some(did) = self.storage.get_deck_id(name.as_native_str())? {
|
||||
self.storage.get_deck(did).map(|opt| opt.unwrap())
|
||||
} else {
|
||||
let mut deck = Deck::new_normal();
|
||||
deck.name = name;
|
||||
self.add_or_update_deck(&mut deck)?;
|
||||
Ok(deck)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a deck based on its human name. If you have a machine name,
|
||||
/// use the method in storage instead.
|
||||
pub(crate) fn get_deck_id(&self, human_name: &str) -> Result<Option<DeckId>> {
|
||||
|
@ -51,6 +51,7 @@ export class DeckConfigState {
|
||||
private selectedIdx: number;
|
||||
private configListSetter!: (val: ConfigListEntry[]) => void;
|
||||
private parentLimitsSetter!: (val: ParentLimits) => void;
|
||||
private modifiedConfigs: Set<DeckConfigId> = new Set();
|
||||
private removedConfigs: DeckConfigId[] = [];
|
||||
private schemaModified: boolean;
|
||||
|
||||
@ -107,8 +108,11 @@ export class DeckConfigState {
|
||||
return;
|
||||
}
|
||||
const uniqueName = this.ensureNewNameUnique(name);
|
||||
this.configs[this.selectedIdx].config.name = uniqueName;
|
||||
this.configs[this.selectedIdx].config.mtimeSecs = 0;
|
||||
const config = this.configs[this.selectedIdx].config;
|
||||
config.name = uniqueName;
|
||||
if (config.id) {
|
||||
this.modifiedConfigs.add(config.id);
|
||||
}
|
||||
this.updateConfigList();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user