Warranties: fix N+1 slowness, filter alignment, and Covers hover
Some checks failed
CI / backend (push) Successful in 1m39s
CI / naming (push) Successful in 2s
CI / frontend (push) Successful in 8s
CI / migrations-mysql (push) Failing after 7s

- Perf: list_warranties did a db.session.get(Asset) per link per warranty
  (~1.8s for the full list). Eager-load the links and batch-fetch every linked
  asset in one query -> ~0.19s.
- Filters: the "Status" label wrapped its select onto a second line, so the
  dropdown sat above the search box; keep the label inline so they align.
- Covers: each asset chip now shows the asset name (often the hostname/alias) on
  hover, keeping the machine number as the label.
This commit is contained in:
cproudlock
2026-07-13 14:49:36 -04:00
parent 4a74a1a405
commit 760b00f4d1
2 changed files with 20 additions and 6 deletions

View File

@@ -9,6 +9,7 @@ from datetime import date, datetime, timezone
from flask import Blueprint, request
from flask_jwt_extended import jwt_required
from sqlalchemy.orm import joinedload
from shopdb.api import (
db, Asset,
@@ -41,12 +42,15 @@ def _asset_summary(asset):
}
def _warranty_payload(warranty, today=None):
"""to_dict plus the linked-asset summaries."""
def _warranty_payload(warranty, today=None, assetmap=None):
"""to_dict plus the linked-asset summaries. Pass assetmap (assetid -> Asset)
to avoid a per-link query when serializing a list; without it, falls back to
a per-link get (fine for a single warranty)."""
data = warranty.to_dict(today)
assets = []
for link in warranty.links:
asset = db.session.get(Asset, link.assetid)
asset = assetmap.get(link.assetid) if assetmap is not None \
else db.session.get(Asset, link.assetid)
if asset:
assets.append(_asset_summary(asset))
data['assets'] = assets
@@ -86,10 +90,17 @@ def list_warranties():
if assetid:
query = (query.join(WarrantyAsset, WarrantyAsset.warrantyid == Warranty.warrantyid)
.filter(WarrantyAsset.assetid == assetid))
warranties = query.order_by(Warranty.enddate.is_(None), Warranty.enddate).all()
warranties = (query.options(joinedload(Warranty.links))
.order_by(Warranty.enddate.is_(None), Warranty.enddate).all())
# Batch-fetch every linked asset in ONE query (was N+1: a db.session.get per
# link per warranty, ~1.8s for the full list).
assetids = {link.assetid for w in warranties for link in w.links}
assetmap = ({a.assetid: a for a in Asset.query.filter(Asset.assetid.in_(assetids)).all()}
if assetids else {})
today = date.today()
items = [_warranty_payload(w, today) for w in warranties]
items = [_warranty_payload(w, today, assetmap) for w in warranties]
status_filter = request.args.get('status')
if status_filter: