mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
Default to current deck in csv import if settings allow it (#2527)
* Default to current deck in csv import if settings allow it Reuses defaults_for_adding(). In the future we might also want to update the last deck/notetype on successful completion, if entries weren't specified in the file. https://forums.ankiweb.net/t/importing-new-notes-to-wrong-deck-in-anki-2-1-63/30598 * Address review feedback from Rumo
This commit is contained in:
parent
7f6c410ca5
commit
f758b33346
6 changed files with 42 additions and 58 deletions
|
@ -114,7 +114,8 @@ message CsvMetadataRequest {
|
|||
string path = 1;
|
||||
optional CsvMetadata.Delimiter delimiter = 2;
|
||||
optional int64 notetype_id = 3;
|
||||
optional bool is_html = 4;
|
||||
optional int64 deck_id = 4;
|
||||
optional bool is_html = 5;
|
||||
}
|
||||
|
||||
// Column indices are 1-based to make working with them in TS easier, where
|
||||
|
|
|
@ -50,8 +50,8 @@ impl Collection {
|
|||
})
|
||||
}
|
||||
|
||||
/// The currently selected deck, the home deck of the provided card, or the
|
||||
/// default deck.
|
||||
/// The currently selected deck, the home deck of the provided card if
|
||||
/// current deck is filtered, or the default deck.
|
||||
fn get_current_deck_for_adding(
|
||||
&mut self,
|
||||
home_deck_of_reviewer_card: DeckId,
|
||||
|
|
|
@ -88,6 +88,7 @@ impl ImportExportService for Backend {
|
|||
&input.path,
|
||||
delimiter,
|
||||
input.notetype_id.map(Into::into),
|
||||
input.deck_id.map(Into::into),
|
||||
input.is_html,
|
||||
)
|
||||
})
|
||||
|
|
|
@ -42,10 +42,11 @@ impl Collection {
|
|||
path: &str,
|
||||
delimiter: Option<Delimiter>,
|
||||
notetype_id: Option<NotetypeId>,
|
||||
deck_id: Option<DeckId>,
|
||||
is_html: Option<bool>,
|
||||
) -> Result<CsvMetadata> {
|
||||
let mut reader = open_file(path)?;
|
||||
self.get_reader_metadata(&mut reader, delimiter, notetype_id, is_html)
|
||||
self.get_reader_metadata(&mut reader, delimiter, notetype_id, deck_id, is_html)
|
||||
}
|
||||
|
||||
fn get_reader_metadata(
|
||||
|
@ -53,6 +54,7 @@ impl Collection {
|
|||
mut reader: impl Read + Seek,
|
||||
delimiter: Option<Delimiter>,
|
||||
notetype_id: Option<NotetypeId>,
|
||||
deck_id: Option<DeckId>,
|
||||
is_html: Option<bool>,
|
||||
) -> Result<CsvMetadata> {
|
||||
let mut metadata = CsvMetadata::from_config(self);
|
||||
|
@ -62,9 +64,8 @@ impl Collection {
|
|||
maybe_set_fallback_is_html(&mut metadata, &records, is_html)?;
|
||||
set_preview(&mut metadata, &records)?;
|
||||
maybe_set_fallback_columns(&mut metadata)?;
|
||||
self.maybe_set_fallback_notetype(&mut metadata, notetype_id)?;
|
||||
self.maybe_set_notetype_and_deck(&mut metadata, notetype_id, deck_id)?;
|
||||
self.maybe_init_notetype_map(&mut metadata)?;
|
||||
self.maybe_set_fallback_deck(&mut metadata)?;
|
||||
|
||||
Ok(metadata)
|
||||
}
|
||||
|
@ -176,37 +177,33 @@ impl Collection {
|
|||
}
|
||||
}
|
||||
|
||||
fn maybe_set_fallback_notetype(
|
||||
/// Ensure notetype and deck are set.
|
||||
///
|
||||
/// - When the UI is first loaded, both notetype and deck arguments will be
|
||||
/// None.
|
||||
/// - When the UI refreshes due to user changes, the currently-selected deck
|
||||
/// and notetype will be provided.
|
||||
/// - Metadata may already have deck and notetype set, if those directives
|
||||
/// were present in the file to import. In the UI refresh case, we
|
||||
/// override them with the current UI values, so that the user can adjust
|
||||
/// the deck/notetype if they wish.
|
||||
/// - In the initial load case, if notetype/deck were not specified in file,
|
||||
/// we apply the defaults from defaults_for_adding().
|
||||
pub(crate) fn maybe_set_notetype_and_deck(
|
||||
&mut self,
|
||||
metadata: &mut CsvMetadata,
|
||||
metadata: &mut crate::pb::import_export::CsvMetadata,
|
||||
notetype_id: Option<NotetypeId>,
|
||||
deck_id: Option<DeckId>,
|
||||
) -> Result<()> {
|
||||
if let Some(ntid) = notetype_id {
|
||||
metadata.notetype = Some(CsvNotetype::new_global(ntid));
|
||||
} else if metadata.notetype.is_none() {
|
||||
metadata.notetype = Some(CsvNotetype::new_global(self.fallback_notetype_id()?));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn maybe_set_fallback_deck(&mut self, metadata: &mut CsvMetadata) -> Result<()> {
|
||||
if metadata.deck.is_none() {
|
||||
metadata.deck = Some(CsvDeck::DeckId(
|
||||
metadata
|
||||
.notetype_id()
|
||||
.and_then(|ntid| self.default_deck_for_notetype(ntid).transpose())
|
||||
.unwrap_or_else(|| {
|
||||
self.get_current_deck().map(|deck| {
|
||||
if deck.is_filtered() {
|
||||
DeckId(1)
|
||||
} else {
|
||||
deck.id
|
||||
}
|
||||
})
|
||||
})?
|
||||
.0,
|
||||
let defaults = self.defaults_for_adding(DeckId(0))?;
|
||||
if metadata.notetype.is_none() || notetype_id.is_some() {
|
||||
metadata.notetype = Some(CsvNotetype::new_global(
|
||||
notetype_id.unwrap_or(defaults.notetype_id),
|
||||
));
|
||||
}
|
||||
if metadata.deck.is_none() || deck_id.is_some() {
|
||||
metadata.deck = Some(CsvDeck::DeckId(deck_id.unwrap_or(defaults.deck_id).0));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -234,18 +231,6 @@ impl Collection {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fallback_notetype_id(&mut self) -> Result<NotetypeId> {
|
||||
Ok(if let Some(notetype_id) = self.get_current_notetype_id() {
|
||||
notetype_id
|
||||
} else {
|
||||
self.storage
|
||||
.get_all_notetype_names()?
|
||||
.first()
|
||||
.or_invalid("collection has no notetypes")?
|
||||
.0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CsvMetadata {
|
||||
|
@ -524,14 +509,6 @@ impl CsvNotetype {
|
|||
}
|
||||
|
||||
impl CsvMetadata {
|
||||
fn notetype_id(&self) -> Option<NotetypeId> {
|
||||
if let Some(CsvNotetype::GlobalNotetype(ref global)) = self.notetype {
|
||||
Some(NotetypeId(global.id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn meta_columns(&self) -> HashSet<usize> {
|
||||
let mut columns = HashSet::new();
|
||||
if let Some(CsvDeck::DeckColumn(deck_column)) = self.deck {
|
||||
|
@ -579,7 +556,7 @@ mod test {
|
|||
metadata!($col, $csv, None)
|
||||
};
|
||||
($col:expr,$csv:expr, $delim:expr) => {
|
||||
$col.get_reader_metadata(Cursor::new($csv.as_bytes()), $delim, None, None)
|
||||
$col.get_reader_metadata(Cursor::new($csv.as_bytes()), $delim, None, None, None)
|
||||
.unwrap()
|
||||
};
|
||||
}
|
||||
|
|
|
@ -56,17 +56,20 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
deckColumn,
|
||||
guidColumn,
|
||||
);
|
||||
$: getCsvMetadata(path, delimiter, undefined, isHtml).then((meta) => {
|
||||
$: getCsvMetadata(path, delimiter, undefined, undefined, isHtml).then((meta) => {
|
||||
columnLabels = meta.columnLabels;
|
||||
preview = meta.preview;
|
||||
});
|
||||
$: if (globalNotetype?.id !== lastNotetypeId || delimiter !== lastDelimeter) {
|
||||
lastNotetypeId = globalNotetype?.id;
|
||||
lastDelimeter = delimiter;
|
||||
getCsvMetadata(path, delimiter, globalNotetype?.id).then((meta) => {
|
||||
getCsvMetadata(path, delimiter, globalNotetype?.id, deckId || undefined).then(
|
||||
(meta) => {
|
||||
globalNotetype = meta.globalNotetype ?? null;
|
||||
deckId = meta.deckId ?? null;
|
||||
tagsColumn = meta.tagsColumn;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async function onImport(): Promise<void> {
|
||||
|
|
|
@ -60,6 +60,7 @@ export async function getCsvMetadata(
|
|||
path: string,
|
||||
delimiter?: ImportExport.CsvMetadata.Delimiter,
|
||||
notetypeId?: number,
|
||||
deckId?: number,
|
||||
isHtml?: boolean,
|
||||
): Promise<ImportExport.CsvMetadata> {
|
||||
return importExport.getCsvMetadata(
|
||||
|
@ -67,6 +68,7 @@ export async function getCsvMetadata(
|
|||
path,
|
||||
delimiter,
|
||||
notetypeId,
|
||||
deckId,
|
||||
isHtml,
|
||||
}),
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue