The Shelves layer: where every box physically lives
Eric's spec, all nine points. Two committed local-only stores follow
the local_games.json pattern — furniture.json (units of openings with
interior dims; a dimensionless opening is a virtual spot like a travel
case) and locations.json (game key -> opening + note). Shelf layouts
are nobody's data but the owner's; nothing touches upload.
The Shelves page builds furniture without hand-editing JSON — the
acceptance bar (two double-wides above three rows of four cubes, two
bookcases, a travel case) is a TEST, driven entirely through the
endpoints the UI calls. Presets for Kallax/Billy/custom/virtual,
grid creation with A1-style labels, openings editable/deletable/
reorderable. Units render as grids: zone, count, fill bar (stacked
thinnest-axis vs interior height), ⚠ on overfull or any resident that
can't fit. Openings open as a modal — a bottom sheet at phone widths,
search-first with thumb-sized targets for the moving-day loop.
Unshelved games list alongside with one-tap suggestions (only openings
they verifiably fit, with room).
Containment composes: a game stored inside another box inherits its
container's location, rides along in the opening's resident list
(marked), and refuses direct assignment naming its container. The
detail page's where-it-lives card gains the picker (openings grouped
by unit, each labeled fits / doesn't fit / can't verify) plus virtual
notes ("lent to Sarah, June"); the Library list shows a location line,
filters by unit or unshelved, and search matches location text and
zones.
bggpipe dims drops its hardcoded Kallax for the user's actual
furniture: per-opening capacity, overfull and misfit warnings,
unshelved count. bggpipe shelve --import loads a name,opening CSV
(ids or labels), rejecting — never guessing — unknown names, ambiguous
copies, unknown/ambiguous openings, misfits, and contained games.
Ten new tests incl. the acceptance flow, inheritance, CSV rejects,
and a phone-sheet smoke; 372 total.
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
e85f72c546
commit
4f446f6f2a
+38
-17
@@ -8,19 +8,8 @@ import pytest
|
||||
import typer
|
||||
|
||||
from bggpipe.config import Config
|
||||
from bggpipe.dims import fits_kallax, run_dims_report
|
||||
|
||||
|
||||
def test_fits_kallax_tries_every_orientation():
|
||||
assert fits_kallax(11.6, 11.6, 2.8) # ordinary big-box
|
||||
# too tall to stand, but slides in lying down: depth axis takes 15.0
|
||||
assert fits_kallax(15.0, 12.0, 3.0)
|
||||
# two axes over the opening: no orientation works
|
||||
assert not fits_kallax(16.2, 16.2, 4.0)
|
||||
# fits the opening but too deep to close the wall behind it
|
||||
assert not fits_kallax(12.0, 12.0, 15.5)
|
||||
# exact boundary counts as fitting
|
||||
assert fits_kallax(13.2, 13.2, 15.4)
|
||||
from bggpipe.dims import run_dims_report
|
||||
from bggpipe.shelves import save_furniture, save_locations
|
||||
|
||||
|
||||
def test_report_buckets_misfits_and_unknowns(tmp_path, capsys):
|
||||
@@ -63,6 +52,7 @@ def test_report_buckets_misfits_and_unknowns(tmp_path, capsys):
|
||||
}
|
||||
)
|
||||
)
|
||||
# no furniture yet: sizes-only report, pointed at the Shelves page
|
||||
summary = run_dims_report(cfg)
|
||||
assert summary["by_source"] == {
|
||||
"version": 1,
|
||||
@@ -70,12 +60,43 @@ def test_report_buckets_misfits_and_unknowns(tmp_path, capsys):
|
||||
"conflicting": 1,
|
||||
"absent": 1,
|
||||
}
|
||||
assert summary["misfits"] == ["Monster Box"]
|
||||
# can't verify is NOT the same as fits: both unknowns are named
|
||||
assert summary["misfits"] == []
|
||||
assert summary["unknown"] == ["Argued About", "Never Measured"]
|
||||
out = capsys.readouterr().out
|
||||
assert "do NOT fit" in out and "Monster Box" in out
|
||||
assert "can't be verified" in out and "Never Measured" in out
|
||||
assert "No furniture on file" in out
|
||||
|
||||
# with furniture: per-opening capacity, misfit and overfull warnings
|
||||
save_furniture(
|
||||
cfg,
|
||||
[
|
||||
{
|
||||
"name": "Den",
|
||||
"openings": [
|
||||
{
|
||||
"id": "den-a1",
|
||||
"label": "A1",
|
||||
"zone": "",
|
||||
"width_in": 13.25,
|
||||
"height_in": 13.25,
|
||||
"depth_in": 15.4,
|
||||
}
|
||||
],
|
||||
}
|
||||
],
|
||||
)
|
||||
save_locations(
|
||||
cfg,
|
||||
{
|
||||
"1": {"opening_id": "den-a1", "note": ""},
|
||||
"2": {"opening_id": "den-a1", "note": ""},
|
||||
},
|
||||
)
|
||||
summary = run_dims_report(cfg)
|
||||
assert summary["misfits"] == ["Monster Box"]
|
||||
out = capsys.readouterr().out
|
||||
assert "doesn't fit: Monster Box" in out
|
||||
assert "unshelved" in out # the conflicting + absent games have no home
|
||||
assert "can't be size-verified" in out and "Never Measured" in out
|
||||
|
||||
|
||||
def test_report_without_games_json_exits_with_guidance(tmp_path):
|
||||
|
||||
Reference in New Issue
Block a user