feat: drag-reorder slots

pool.reorder() permutes slots (validated permutation) and keeps the
active selection on its slot; exposed via /grid_pool/reorder. The grid
thumbnails are drag handles; dropping on another cell reorders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-21 15:12:53 +02:00
parent b115a0d449
commit 25e89ada2b
6 changed files with 91 additions and 0 deletions
+4
View File
@@ -22,5 +22,9 @@ def handle_list(base, pool_id):
return pool.read_manifest(base, pool_id)
def handle_reorder(base, pool_id, order):
return pool.reorder(base, pool_id, order)
def handle_set_mask(base, pool_id, index, mask_png_bytes):
return pool.set_mask(base, pool_id, index, mask_png_bytes) # Task 12
+14
View File
@@ -112,6 +112,20 @@ def set_label(base_dir, pool_id, index, label):
return m
def reorder(base_dir, pool_id, order):
m = read_manifest(base_dir, pool_id)
n = len(m["slots"])
# order must be a permutation of range(n) — otherwise leave untouched
if sorted(order) != list(range(n)):
return m
old_active = m.get("active", 0)
m["slots"] = [m["slots"][i] for i in order]
m["active"] = order.index(old_active) if old_active in order else 0
m["active"] = _clamp_active(m)
write_manifest(base_dir, pool_id, m)
return m
def set_mask(base_dir, pool_id, index, mask_bytes):
m = read_manifest(base_dir, pool_id)
if not (0 <= index < len(m["slots"])):
+7
View File
@@ -60,6 +60,13 @@ async def _set_mask(request):
return web.json_response(m)
@routes.post("/grid_pool/reorder")
async def _reorder(request):
body = await request.json()
order = [int(i) for i in body["order"]]
return web.json_response(handlers.handle_reorder(_base(), body["pool_id"], order))
@routes.get("/grid_pool/list")
async def _list(request):
pool_id = request.query.get("pool_id", "default")