add a separate 'rename deck' method

This commit is contained in:
Damien Elmes 2021-03-11 18:54:30 +10:00
parent 4bd120cc4b
commit 984e2c2666
7 changed files with 84 additions and 43 deletions

View file

@ -250,11 +250,13 @@ class DeckManager:
deck=to_json_bytes(g), preserve_usn_and_mtime=preserve_usn
)
def rename(self, g: Deck, newName: str) -> None:
def rename(self, deck: Union[Deck, int], new_name: str) -> None:
"Rename deck prefix to NAME if not exists. Updates children."
g["name"] = newName
self.update(g, preserve_usn=False)
return
if isinstance(deck, int):
deck_id = deck
else:
deck_id = deck["id"]
self.col._backend.rename_deck(deck_id=deck_id, new_name=new_name)
# Drag/drop
#############################################################

View file

@ -132,6 +132,7 @@ service DecksService {
rpc NewDeckLegacy(Bool) returns (Json);
rpc RemoveDeck(DeckID) returns (Empty);
rpc DragDropDecks(DragDropDecksIn) returns (Empty);
rpc RenameDeck(RenameDeckIn) returns (Empty);
}
service NotesService {
@ -1448,3 +1449,8 @@ message DeckAndNotetype {
int64 deck_id = 1;
int64 notetype_id = 2;
}
message RenameDeckIn {
int64 deck_id = 1;
string new_name = 2;
}

View file

@ -124,4 +124,21 @@ impl DecksService for Backend {
self.with_col(|col| col.drag_drop_decks(&source_dids, target_did))
.map(Into::into)
}
fn rename_deck(&self, input: pb::RenameDeckIn) -> Result<pb::Empty> {
self.with_col(|col| col.rename_deck(input.deck_id.into(), &input.new_name))
.map(Into::into)
}
}
impl From<pb::DeckId> for DeckID {
fn from(did: pb::DeckId) -> Self {
DeckID(did.did)
}
}
impl From<DeckID> for pb::DeckId {
fn from(did: DeckID) -> Self {
pb::DeckId { did: did.0 }
}
}

View file

@ -63,18 +63,6 @@ impl From<pb::NoteTypeId> for NoteTypeID {
}
}
impl From<pb::DeckId> for DeckID {
fn from(did: pb::DeckId) -> Self {
DeckID(did.did)
}
}
impl From<DeckID> for pb::DeckId {
fn from(did: DeckID) -> Self {
pb::DeckId { did: did.0 }
}
}
impl From<pb::DeckConfigId> for DeckConfID {
fn from(dcid: pb::DeckConfigId) -> Self {
DeckConfID(dcid.dcid)

View file

@ -292,30 +292,39 @@ impl Collection {
})
}
pub(crate) fn update_deck(&mut self, deck: &mut Deck) -> Result<()> {
pub fn update_deck(&mut self, deck: &mut Deck) -> Result<()> {
self.transact(Some(UndoableOpKind::UpdateDeck), |col| {
let usn = col.usn()?;
col.prepare_deck_for_update(deck, usn)?;
let existing_deck = col.storage.get_deck(deck.id)?.ok_or(AnkiError::NotFound)?;
col.update_deck_inner(deck, existing_deck, col.usn()?)
})
}
pub fn rename_deck(&mut self, did: DeckID, new_human_name: &str) -> Result<()> {
self.transact(Some(UndoableOpKind::RenameDeck), |col| {
let existing_deck = col.storage.get_deck(did)?.ok_or(AnkiError::NotFound)?;
let mut deck = existing_deck.clone();
deck.name = human_deck_name_to_native(new_human_name);
col.update_deck_inner(&mut deck, existing_deck, col.usn()?)
})
}
fn update_deck_inner(&mut self, deck: &mut Deck, original: Deck, usn: Usn) -> Result<()> {
self.prepare_deck_for_update(deck, usn)?;
deck.set_modified(usn);
if let Some(existing_deck) = col.storage.get_deck(deck.id)? {
let name_changed = existing_deck.name != deck.name;
let name_changed = original.name != deck.name;
if name_changed {
// match closest parent name
col.match_or_create_parents(deck, usn)?;
self.match_or_create_parents(deck, usn)?;
// rename children
col.rename_child_decks(&existing_deck, &deck.name, usn)?;
self.rename_child_decks(&original, &deck.name, usn)?;
}
col.update_single_deck_undoable(deck, &existing_deck)?;
self.update_single_deck_undoable(deck, original)?;
if name_changed {
// after updating, we need to ensure all grandparents exist, which may not be the case
// in the parent->child case
col.create_missing_parents(&deck.name, usn)?;
self.create_missing_parents(&deck.name, usn)?;
}
Ok(())
} else {
Err(AnkiError::invalid_input("updating non-existent deck"))
}
})
}
/// Add/update a single deck when syncing/importing. Ensures name is unique
@ -377,7 +386,7 @@ impl Collection {
let new_name = format!("{}\x1f{}", new_name, child_only.join("\x1f"));
child.name = new_name;
child.set_modified(usn);
self.update_single_deck_undoable(&mut child, &original)?;
self.update_single_deck_undoable(&mut child, original)?;
}
Ok(())
@ -600,7 +609,7 @@ impl Collection {
deck.reset_stats_if_day_changed(today);
mutator(&mut deck.common);
deck.set_modified(usn);
self.update_single_deck_undoable(deck, &original)
self.update_single_deck_undoable(deck, original)
}
pub fn drag_drop_decks(
@ -761,6 +770,23 @@ mod test {
col.add_or_update_deck(&mut middle)?;
assert_eq!(middle.name, "other+");
// public function takes human name
col.rename_deck(middle.id, "one::two")?;
assert_eq!(
sorted_names(&col),
vec![
"Default",
"one",
"one::two",
"one::two::baz",
"one::two::baz2",
"other",
"quux",
"quux::foo",
"quux::foo::baz",
]
);
Ok(())
}

View file

@ -22,7 +22,7 @@ impl Collection {
.storage
.get_deck(deck.id)?
.ok_or_else(|| AnkiError::invalid_input("deck disappeared"))?;
self.update_single_deck_undoable(&mut *deck, &current)
self.update_single_deck_undoable(&mut *deck, current)
}
UndoableDeckChange::Removed(deck) => self.restore_deleted_deck(*deck),
UndoableDeckChange::GraveAdded(e) => self.remove_deck_grave(e.0, e.1),
@ -52,10 +52,10 @@ impl Collection {
pub(super) fn update_single_deck_undoable(
&mut self,
deck: &mut Deck,
original: &Deck,
original: Deck,
) -> Result<()> {
self.state.deck_cache.clear();
self.save_undo(UndoableDeckChange::Updated(Box::new(original.clone())));
self.save_undo(UndoableDeckChange::Updated(Box::new(original)));
self.storage.update_deck(deck)
}

View file

@ -11,6 +11,7 @@ pub enum UndoableOpKind {
Bury,
RemoveDeck,
RemoveNote,
RenameDeck,
Suspend,
UnburyUnsuspend,
UpdateCard,
@ -35,6 +36,7 @@ impl Collection {
UndoableOpKind::Bury => TR::StudyingBury,
UndoableOpKind::RemoveDeck => TR::DecksDeleteDeck,
UndoableOpKind::RemoveNote => TR::StudyingDeleteNote,
UndoableOpKind::RenameDeck => TR::ActionsRenameDeck,
UndoableOpKind::Suspend => TR::StudyingSuspend,
UndoableOpKind::UnburyUnsuspend => TR::UndoUnburyUnsuspend,
UndoableOpKind::UpdateCard => TR::UndoUpdateCard,