From d62a5637d848a537e69a35c79c9d59ebdb7de155 Mon Sep 17 00:00:00 2001 From: Nathaniel Ledford Date: Fri, 9 Oct 2026 14:44:41 -0400 Subject: [PATCH] LRC-LIB-KEYWORDS: the filter follows a keyword moved into a new parent `keyword.move` worked out where the keyword landed from the parent's spelling in the library, and fell back to the top level when the parent didn't exist yet, while the catalog made that parent: the keyword filter stayed on the old path and the grid showed nothing. It now lands the filter where the catalog puts the keyword. Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/cmd/keywords.rs | 11 ++++++----- crates/engine/src/tests_keyword_list.rs | 13 +++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/crates/engine/src/cmd/keywords.rs b/crates/engine/src/cmd/keywords.rs index 00f6d24d2..1e9dacbae 100644 --- a/crates/engine/src/cmd/keywords.rs +++ b/crates/engine/src/cmd/keywords.rs @@ -301,15 +301,16 @@ pub fn specs() -> Vec { Some(Value::Null) => None, _ => return Err(bad("keyword.move", "`parent` is a keyword, or null for the top level")), }; + // where it lands, as the catalog spells it: a parent that doesn't exist yet is made + let leaf = from.rsplit('|').next().unwrap_or(&from).to_string(); + let to = match parent.as_deref().map(|k| s.catalog.keyword_path(k).unwrap_or_else(|| clean(k))).filter(|k| !k.is_empty()) { + Some(parent) => format!("{parent}|{leaf}"), + None => leaf, + }; let op = s .catalog .move_keyword_ops(&from, parent.as_deref(), bool_or(p, "merge", false)) .map_err(|e| refused("keyword.move", e, ": moving would merge the two (merge: true)"))?; - let leaf = from.rsplit('|').next().unwrap_or(&from).to_string(); - let to = match parent.as_deref().and_then(|k| s.catalog.keyword_path(k)) { - Some(parent) => format!("{parent}|{leaf}"), - None => leaf, - }; commit_keywords(s, "Move Keyword", op, |k| Some(if is_under(k, &from) { reparent(k, &from, &to) } else { k.to_string() })) } ), diff --git a/crates/engine/src/tests_keyword_list.rs b/crates/engine/src/tests_keyword_list.rs index 18932dd3d..eba8e34b0 100644 --- a/crates/engine/src/tests_keyword_list.rs +++ b/crates/engine/src/tests_keyword_list.rs @@ -129,3 +129,16 @@ fn purging_unused_keywords() { s.execute("edit.undo", &json!({})).unwrap(); assert!(s.execute("keyword.info", &json!({"keyword": "Weddings"})).is_ok()); } + +/// Moving a keyword into a parent that doesn't exist yet makes that parent, and the keyword filter +/// follows the keyword there (the grid kept filtering by the old path, and showed nothing). +#[test] +fn the_filter_follows_a_keyword_moved_into_a_new_parent() { + let mut s = Session::with_demo(); + let id = s.visible_cloned()[0].0; + s.execute("photo.setMeta", &json!({"ids": [id], "keywords": ["Rome"]})).unwrap(); + s.execute("library.filter", &json!({"keyword": "Rome"})).unwrap(); + s.execute("keyword.move", &json!({"keyword": "rome", "parent": "Italy"})).unwrap(); + assert_eq!(keywords_of(&s, id), ["Italy|Rome"]); + assert_eq!(s.filter.keyword.as_deref(), Some("Italy|Rome")); +}