Split dashboard into home page and battery list page
This commit is contained in:
@@ -97,7 +97,7 @@ def create_app(config_object="config"):
|
||||
poller.start()
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Dashboard
|
||||
# Home / Battery list
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
@app.route("/sw.js")
|
||||
@@ -106,26 +106,14 @@ def create_app(config_object="config"):
|
||||
mimetype="application/javascript")
|
||||
|
||||
@app.route("/")
|
||||
def dashboard():
|
||||
batteries = db.query(Battery).order_by(Battery.label).all()
|
||||
storage_locations = [
|
||||
r[0] for r in db.query(Battery.storage_location)
|
||||
.filter(Battery.storage_location.isnot(None))
|
||||
.distinct().order_by(Battery.storage_location).all()
|
||||
]
|
||||
devices = db.query(Device).order_by(Device.name).all()
|
||||
devices_with_slots = [d for d in devices if d.installed_count() < d.battery_slots and not d.has_children()]
|
||||
def home():
|
||||
batteries = db.query(Battery).all()
|
||||
today = date.today()
|
||||
one_year_ago = (today - timedelta(days=365)).isoformat()
|
||||
total_charges = db.query(func.count(ChargeLog.id)).scalar() or 0
|
||||
charges_last_year = (db.query(func.count(ChargeLog.id))
|
||||
.filter(ChargeLog.charged_date >= one_year_ago)
|
||||
.scalar()) or 0
|
||||
last_charged_map = {
|
||||
r[0]: r[1]
|
||||
for r in db.query(ChargeLog.battery_id, func.max(ChargeLog.charged_date))
|
||||
.group_by(ChargeLog.battery_id).all()
|
||||
}
|
||||
active = [b for b in batteries if b.status in ("available", "installed")]
|
||||
needs_attention = {
|
||||
"low_capacity": [
|
||||
@@ -138,14 +126,57 @@ def create_app(config_object="config"):
|
||||
if b.battery_percentage is not None and b.battery_percentage < 20
|
||||
] if ha_client.enabled else [],
|
||||
}
|
||||
return render_template("dashboard.html", batteries=batteries,
|
||||
total_batteries = len(batteries)
|
||||
avail_count = sum(1 for b in batteries if b.status == "available")
|
||||
installed_count = sum(1 for b in batteries if b.status == "installed")
|
||||
retired_count = sum(1 for b in batteries if b.status == "retired")
|
||||
devices = db.query(Device).filter(Device.parent_id == None).all()
|
||||
total_devices = len(devices)
|
||||
full_devices = sum(
|
||||
1 for d in devices
|
||||
if d.effective_slots() > 0 and d.effective_installed_count() >= d.effective_slots()
|
||||
)
|
||||
partial_devices = sum(
|
||||
1 for d in devices
|
||||
if 0 < d.effective_installed_count() < d.effective_slots()
|
||||
)
|
||||
empty_devices = sum(1 for d in devices if d.effective_installed_count() == 0)
|
||||
return render_template("home.html",
|
||||
total_batteries=total_batteries,
|
||||
avail_count=avail_count,
|
||||
installed_count=installed_count,
|
||||
retired_count=retired_count,
|
||||
total_devices=total_devices,
|
||||
full_devices=full_devices,
|
||||
partial_devices=partial_devices,
|
||||
empty_devices=empty_devices,
|
||||
total_charges=total_charges,
|
||||
charges_last_year=charges_last_year,
|
||||
needs_attention=needs_attention,
|
||||
ha_enabled=ha_client.enabled,
|
||||
today=today)
|
||||
|
||||
@app.route("/battery/")
|
||||
def battery_list():
|
||||
batteries = db.query(Battery).order_by(Battery.label).all()
|
||||
storage_locations = [
|
||||
r[0] for r in db.query(Battery.storage_location)
|
||||
.filter(Battery.storage_location.isnot(None))
|
||||
.distinct().order_by(Battery.storage_location).all()
|
||||
]
|
||||
devices = db.query(Device).order_by(Device.name).all()
|
||||
devices_with_slots = [d for d in devices if d.installed_count() < d.battery_slots and not d.has_children()]
|
||||
today = date.today()
|
||||
last_charged_map = {
|
||||
r[0]: r[1]
|
||||
for r in db.query(ChargeLog.battery_id, func.max(ChargeLog.charged_date))
|
||||
.group_by(ChargeLog.battery_id).all()
|
||||
}
|
||||
return render_template("battery_list.html", batteries=batteries,
|
||||
storage_locations=storage_locations, devices=devices,
|
||||
devices_with_slots=devices_with_slots,
|
||||
ha_enabled=ha_client.enabled,
|
||||
total_charges=total_charges,
|
||||
charges_last_year=charges_last_year,
|
||||
last_charged_map=last_charged_map,
|
||||
needs_attention=needs_attention,
|
||||
today=today)
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
@@ -201,7 +232,7 @@ def create_app(config_object="config"):
|
||||
purchase_date=purchase_date, storage_location=storage_location))
|
||||
db.commit()
|
||||
flash(f"Added {count} {brand} batter{'y' if count == 1 else 'ies'}.", "success")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
|
||||
brands = [r[0] for r in db.query(Battery.brand).distinct().order_by(Battery.brand).all()]
|
||||
storage_locations = [
|
||||
@@ -454,7 +485,7 @@ def create_app(config_object="config"):
|
||||
battery.device_id = device.id
|
||||
db.commit()
|
||||
flash(f"{battery.label} assigned to {device.name}.", "success")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
|
||||
return render_template("assign.html", battery=battery, devices=devices_with_slots)
|
||||
|
||||
@@ -471,7 +502,7 @@ def create_app(config_object="config"):
|
||||
battery.device_id = None
|
||||
db.commit()
|
||||
flash(f"{battery.label} unassigned and marked available.", "success")
|
||||
return redirect(_safe_next(url_for("dashboard")))
|
||||
return redirect(_safe_next(url_for("battery_list")))
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Battery — retire
|
||||
@@ -489,7 +520,7 @@ def create_app(config_object="config"):
|
||||
battery.device_id = None
|
||||
db.commit()
|
||||
flash(f"{battery.label} has been retired.", "success")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Battery — unretire
|
||||
@@ -522,7 +553,7 @@ def create_app(config_object="config"):
|
||||
db.delete(battery)
|
||||
db.commit()
|
||||
flash(f"Battery {label} permanently deleted.", "success")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
return render_template("battery_delete.html", battery=battery)
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
@@ -534,7 +565,7 @@ def create_app(config_object="config"):
|
||||
ids = request.form.getlist("battery_ids", type=int)
|
||||
if not ids:
|
||||
flash("No batteries selected.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
|
||||
batteries = db.query(Battery).filter(Battery.id.in_(ids)).all()
|
||||
action = request.form.get("action")
|
||||
@@ -563,7 +594,7 @@ def create_app(config_object="config"):
|
||||
new_brand = request.form.get("new_brand", "").strip()
|
||||
if not new_brand:
|
||||
flash("Brand name is required.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
for b in batteries:
|
||||
b.brand = new_brand
|
||||
db.commit()
|
||||
@@ -572,15 +603,15 @@ def create_app(config_object="config"):
|
||||
device_id = request.form.get("device_id", type=int)
|
||||
if not device_id:
|
||||
flash("Please select a device.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
device = db.get(Device, device_id)
|
||||
if device is None:
|
||||
flash("Device not found.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
|
||||
if device.has_children():
|
||||
flash(f"{device.name} has sub-components; install batteries into those instead.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
|
||||
already_here = [b for b in batteries if b.device_id == device.id]
|
||||
retired_sel = [b for b in batteries if b.is_retired()]
|
||||
@@ -589,7 +620,7 @@ def create_app(config_object="config"):
|
||||
|
||||
if not to_process:
|
||||
flash("No eligible batteries to install.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
|
||||
free_slots = device.battery_slots - device.installed_count()
|
||||
if len(to_process) > free_slots:
|
||||
@@ -598,7 +629,7 @@ def create_app(config_object="config"):
|
||||
f"but {len(to_process)} need installing.",
|
||||
"error",
|
||||
)
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
|
||||
existing_brands = device.installed_brands()
|
||||
new_brands = set(b.brand for b in to_process)
|
||||
@@ -627,10 +658,10 @@ def create_app(config_object="config"):
|
||||
allowed = {"brand", "storage_location"}
|
||||
if field_name not in allowed:
|
||||
flash("Invalid field.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
if field_name == "brand" and not field_value:
|
||||
flash("Brand name is required.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
for b in batteries:
|
||||
setattr(b, field_name, field_value)
|
||||
db.commit()
|
||||
@@ -640,7 +671,7 @@ def create_app(config_object="config"):
|
||||
date_val = _parse_date(request.form.get("charged_date", "").strip())
|
||||
if not date_val:
|
||||
flash("A valid date (YYYY-MM-DD) is required.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
increment = 1 if request.form.get("increment_cycles") else 0
|
||||
for b in batteries:
|
||||
_record_charge(db, b, date_val, increment, notes=None)
|
||||
@@ -654,7 +685,7 @@ def create_app(config_object="config"):
|
||||
else:
|
||||
flash("Unknown action.", "error")
|
||||
|
||||
return redirect(url_for("dashboard"))
|
||||
return redirect(url_for("battery_list"))
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Devices — list
|
||||
|
||||
Reference in New Issue
Block a user