feat: category icons sync + unknown type dashboard widget

- Synced categories table: added Equipment/Appliances with icons,
  removed unused Furniture/Utensils & Serveware
- Updated seed data to match real asset categories
- Added category_health query to /api/stats (finds asset categories
  not in the categories lookup table)
- Added Category Health card to dashboard UI (red warning, shown
  only when unmapped categories exist)
This commit is contained in:
2026-05-31 00:28:07 -04:00
parent 750cde68c9
commit d58834bc56
2 changed files with 288 additions and 33 deletions
+17 -2
View File
@@ -310,8 +310,9 @@ def _seed_if_empty(conn: sqlite3.Connection, table: str, columns: tuple, rows: l
def _seed_data(conn: sqlite3.Connection):
"""Insert default seed data for lookup tables."""
_seed_if_empty(conn, "categories", ("name", "icon"), [
("Furniture", "🪑"), ("Appliances", "🔌"),
("Utensils & Serveware", "🍽️"), ("Equipment", "⚙️"), ("Other", "📦"),
("Bev", "🥤"), ("Snack", "🍿"),
("Food", "🍔"), ("Equipment", "🔧"),
("Appliances", "🔌"), ("Other", "📦"),
])
_seed_if_empty(conn, "key_names", ("name",), [
("MK500",), ("Green Dot",), ("Red Key",), ("Blue Key",),
@@ -1526,6 +1527,19 @@ def get_stats():
).fetchall()
by_make = {r["make"]: r["cnt"] for r in makes}
# Find asset categories not in the categories lookup table
unmapped = conn.execute(
"""SELECT a.category AS name, COUNT(*) AS cnt
FROM assets a LEFT JOIN categories c ON a.category = c.name
WHERE c.id IS NULL AND a.category IS NOT NULL AND a.category != ''
GROUP BY a.category ORDER BY cnt DESC"""
).fetchall()
category_health = {
"unmapped": [{"name": r["name"], "count": r["cnt"]} for r in unmapped],
"total_categories": len(by_category),
"unmapped_count": len(unmapped),
}
conn.close()
return {
"total_assets": total_assets,
@@ -1538,6 +1552,7 @@ def get_stats():
"top_visited": top_visited_list,
"time_on_site": time_on_site,
"by_make": by_make,
"category_health": category_health,
}