v0.1.28 - Version bump and editor/throughput updates

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 22:51:29 +12:00
co-authored by Claude Opus 4.8
parent 3f8279af10
commit 1dd48bc771
10 changed files with 395 additions and 72 deletions
+37 -13
View File
@@ -86,12 +86,17 @@ def _serialize_product_formula(product: Product) -> dict:
def _serialize_mix_row(mix: Mix, *, visible_count: int, product_count: int) -> dict:
# Status is product-driven once a mix has products (Active = at least one
# visible product). A mix with no products yet has nothing to fan out to, so
# it falls back to its own `status` column — that's what lets a brand-new
# mix read as Active instead of being stuck Inactive and hidden.
visible = visible_count > 0 if product_count > 0 else mix.status == "active"
return {
"id": mix.id,
"tenant_id": mix.tenant_id,
"client_name": mix.client_name,
"name": mix.name,
"visible": visible_count > 0,
"visible": visible,
"product_count": product_count,
"visible_product_count": visible_count,
"notes": mix.notes,
@@ -319,6 +324,9 @@ def create_editor_mix(
client_name=payload.client_name.strip(),
name=payload.name.strip(),
notes=payload.notes,
# Active by default so a freshly created mix shows under the default
# "Active" filter rather than being hidden until it has a visible product.
status="active",
)
db.add(mix)
db.flush()
@@ -348,27 +356,43 @@ def update_editor_mix(
raise HTTPException(status_code=404, detail="Mix not found")
updates = payload.model_dump(exclude_unset=True)
# `visible` is a virtual field: it fans out to the visibility of every product
# under the mix rather than mapping to a mix column.
# `visible` is a virtual field: for a mix with products it fans out to the
# visibility of every product; for a product-less mix it maps to the mix's
# own `status` column so the toggle still persists.
visible = updates.pop("visible", None)
product_total = (
db.scalar(
select(func.count())
.select_from(Product)
.where(Product.tenant_id == session.tenant_id, Product.mix_id == mix_id)
)
or 0
)
before = {field: getattr(mix, field) for field in updates}
if visible is not None:
visible_before = db.scalar(
select(func.count())
.select_from(Product)
.where(Product.tenant_id == session.tenant_id, Product.mix_id == mix_id, Product.visible)
)
before["visible"] = bool(visible_before)
if product_total > 0:
visible_before = db.scalar(
select(func.count())
.select_from(Product)
.where(Product.tenant_id == session.tenant_id, Product.mix_id == mix_id, Product.visible)
)
before["visible"] = bool(visible_before)
else:
before["visible"] = mix.status == "active"
for field, value in updates.items():
setattr(mix, field, value)
if visible is not None:
for product in db.scalars(
select(Product).where(Product.tenant_id == session.tenant_id, Product.mix_id == mix_id)
).all():
product.visible = visible
if product_total > 0:
for product in db.scalars(
select(Product).where(Product.tenant_id == session.tenant_id, Product.mix_id == mix_id)
).all():
product.visible = visible
else:
mix.status = "active" if visible else "inactive"
after = dict(updates)
if visible is not None: