diff --git a/frontend/src/views/warranty/WarrantiesList.vue b/frontend/src/views/warranty/WarrantiesList.vue index 4e83353..d26343a 100644 --- a/frontend/src/views/warranty/WarrantiesList.vue +++ b/frontend/src/views/warranty/WarrantiesList.vue @@ -51,7 +51,7 @@ {{ w.enddate ? formatDate(w.enddate) : '-' }} - - {{ a.assetnumber }} + {{ a.assetnumber }} @@ -350,6 +350,9 @@ async function refresh(w) { .muted { color: var(--text-light); } .status-badge { padding: 0.15rem 0.6rem; border-radius: 12px; font-size: 0.78rem; font-weight: 600; } .filters { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem; } +/* Keep the "Status" label + its select on one line so it aligns with the + single-line search box next to it. */ +.filters label { display: inline-flex; align-items: center; gap: 0.4rem; } .filters .form-control { max-width: 320px; } .result-count { color: var(--text-light); font-size: 0.85rem; } .servicelevel-cell { max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } diff --git a/plugins/warranty/api/routes.py b/plugins/warranty/api/routes.py index 41ddb5d..890e322 100644 --- a/plugins/warranty/api/routes.py +++ b/plugins/warranty/api/routes.py @@ -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: