Duplicate a unit: describe the furniture once, stamp out the rest
Eric's ask. duplicate-unit clones the STRUCTURE — openings with their sizes, zones, and descriptions, under fresh ids and the first free "<name> 2"-style name — never the game assignments. And because a copy immediately wants a real name, units gained rename: opening ids are stable through it so locations and export URLs never notice, and a rename-only edit no longer risks wiping the description (the body field learned the None-means-leave-alone convention). Tests pin the disjoint ids, the empty copy, the numbering past taken names, and the wipe-nothing rename. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
co-authored by
Claude Fable 5
parent
e90a53fb6c
commit
10f99e23f5
@@ -875,3 +875,106 @@ def test_unit_descriptions_round_trip(tmp_path):
|
||||
|
||||
saved = _json.loads(cfg.furniture_path.read_text())["units"][0]
|
||||
assert saved["description"] == "now in the study"
|
||||
|
||||
|
||||
def test_duplicate_unit_copies_structure_never_games(tmp_path):
|
||||
games = {
|
||||
"1": {
|
||||
"bgg_id": 1,
|
||||
"name": "Catan",
|
||||
"dims": {
|
||||
"width_in": 11,
|
||||
"length_in": 11,
|
||||
"depth_in": 3,
|
||||
"source": "version",
|
||||
},
|
||||
}
|
||||
}
|
||||
web, cfg = _web(tmp_path, games)
|
||||
web.post(
|
||||
"/api/furniture/add-unit",
|
||||
json={"name": "Kallax", "description": "the original"},
|
||||
)
|
||||
web.post(
|
||||
"/api/furniture/add-openings",
|
||||
json={
|
||||
"unit": "Kallax",
|
||||
"rows": 1,
|
||||
"cols": 2,
|
||||
"zone": "cubes",
|
||||
"width_in": 13.25,
|
||||
"height_in": 13.25,
|
||||
"depth_in": 15.4,
|
||||
},
|
||||
)
|
||||
first = web.get("/api/shelves").json()["units"][0]["openings"][0]["id"]
|
||||
web.post(
|
||||
"/api/furniture/edit-opening", json={"id": first, "description": "top left"}
|
||||
)
|
||||
web.post("/api/locate", json={"key": "1", "opening_id": first})
|
||||
|
||||
web.post("/api/furniture/duplicate-unit", json={"name": "Kallax"})
|
||||
state = web.get("/api/shelves").json()
|
||||
names = [u["name"] for u in state["units"]]
|
||||
assert names == ["Kallax", "Kallax 2"]
|
||||
copy = state["units"][1]
|
||||
assert copy["description"] == "the original"
|
||||
assert [o["label"] for o in copy["openings"]] == ["A1", "A2"]
|
||||
assert copy["openings"][0]["description"] == "top left"
|
||||
# fresh ids, no residents copied
|
||||
original_ids = {o["id"] for o in state["units"][0]["openings"]}
|
||||
copy_ids = {o["id"] for o in copy["openings"]}
|
||||
assert original_ids.isdisjoint(copy_ids)
|
||||
assert all(o["games"] == 0 for o in copy["openings"])
|
||||
# duplicating again numbers past the taken name
|
||||
web.post("/api/furniture/duplicate-unit", json={"name": "Kallax"})
|
||||
names = [u["name"] for u in web.get("/api/shelves").json()["units"]]
|
||||
assert names == ["Kallax", "Kallax 2", "Kallax 3"]
|
||||
|
||||
|
||||
def test_rename_unit_keeps_openings_locations_and_description(tmp_path):
|
||||
games = {
|
||||
"1": {
|
||||
"bgg_id": 1,
|
||||
"name": "Catan",
|
||||
"dims": {
|
||||
"width_in": 11,
|
||||
"length_in": 11,
|
||||
"depth_in": 3,
|
||||
"source": "version",
|
||||
},
|
||||
}
|
||||
}
|
||||
web, cfg = _web(tmp_path, games)
|
||||
web.post(
|
||||
"/api/furniture/add-unit", json={"name": "Kallax", "description": "keep me"}
|
||||
)
|
||||
web.post(
|
||||
"/api/furniture/add-openings",
|
||||
json={
|
||||
"unit": "Kallax",
|
||||
"label": "A1",
|
||||
"width_in": 13.25,
|
||||
"height_in": 13.25,
|
||||
"depth_in": 15.4,
|
||||
},
|
||||
)
|
||||
oid = web.get("/api/shelves").json()["units"][0]["openings"][0]["id"]
|
||||
web.post("/api/locate", json={"key": "1", "opening_id": oid})
|
||||
web.post(
|
||||
"/api/furniture/edit-unit", json={"name": "Kallax", "new_name": "Den wall"}
|
||||
)
|
||||
state = web.get("/api/shelves").json()
|
||||
unit = state["units"][0]
|
||||
assert unit["name"] == "Den wall"
|
||||
assert unit["description"] == "keep me" # rename-only edit wipes nothing
|
||||
assert unit["openings"][0]["games"] == 1 # opening ids stable: game stays
|
||||
# rename onto a taken name refuses
|
||||
web.post("/api/furniture/add-unit", json={"name": "Loft"})
|
||||
assert (
|
||||
web.post(
|
||||
"/api/furniture/edit-unit",
|
||||
json={"name": "Den wall", "new_name": "Loft"},
|
||||
).status_code
|
||||
== 409
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user