Add sub-component support via self-referential device hierarchy
This commit is contained in:
@@ -661,6 +661,12 @@ def create_app(config_object="config"):
|
||||
device_locations = sorted({d.location for d in all_devices if d.location})
|
||||
device_battery_sizes = sorted({d.battery_size for d in all_devices if d.battery_size})
|
||||
|
||||
# Pre-fill parent for "Add Sub-component" links
|
||||
prefill_parent_id = request.args.get("parent_id", "").strip()
|
||||
prefill_parent = None
|
||||
if prefill_parent_id:
|
||||
prefill_parent = db.get(Device, int(prefill_parent_id)) if prefill_parent_id.isdigit() else None
|
||||
|
||||
if request.method == "POST":
|
||||
name = request.form.get("name", "").strip()
|
||||
slots_raw = request.form.get("battery_slots", "1").strip()
|
||||
@@ -669,12 +675,31 @@ def create_app(config_object="config"):
|
||||
battery_size = request.form.get("battery_size", "").strip() or None
|
||||
location = request.form.get("location", "").strip() or None
|
||||
|
||||
# Resolve parent device
|
||||
parent_id_raw = request.form.get("parent_id", "").strip()
|
||||
parent_device = None
|
||||
if parent_id_raw and parent_id_raw.isdigit():
|
||||
parent_device = db.get(Device, int(parent_id_raw))
|
||||
if not parent_device:
|
||||
flash("Parent device not found.", "error")
|
||||
return render_template("device_add.html",
|
||||
device_types=device_types,
|
||||
device_locations=device_locations,
|
||||
device_battery_sizes=device_battery_sizes), 400
|
||||
if parent_device.is_subcomponent():
|
||||
flash("Cannot nest sub-components more than one level deep.", "error")
|
||||
return render_template("device_add.html",
|
||||
device_types=device_types,
|
||||
device_locations=device_locations,
|
||||
device_battery_sizes=device_battery_sizes), 400
|
||||
|
||||
if not name:
|
||||
flash("Device name is required.", "error")
|
||||
return render_template("device_add.html",
|
||||
device_types=device_types,
|
||||
device_locations=device_locations,
|
||||
device_battery_sizes=device_battery_sizes), 400
|
||||
device_battery_sizes=device_battery_sizes,
|
||||
prefill_parent=parent_device), 400
|
||||
|
||||
if not battery_size:
|
||||
flash("Battery size is required.", "error")
|
||||
@@ -683,7 +708,8 @@ def create_app(config_object="config"):
|
||||
device_locations=device_locations,
|
||||
device_battery_sizes=device_battery_sizes,
|
||||
form_name=name, form_notes=notes or "",
|
||||
form_device_type=request.form.get("device_type", "")), 400
|
||||
form_device_type=request.form.get("device_type", ""),
|
||||
prefill_parent=parent_device), 400
|
||||
|
||||
try:
|
||||
slots = int(slots_raw)
|
||||
@@ -696,7 +722,8 @@ def create_app(config_object="config"):
|
||||
device_locations=device_locations,
|
||||
device_battery_sizes=device_battery_sizes,
|
||||
form_name=name, form_notes=notes or "",
|
||||
form_device_type=request.form.get("device_type", "")), 400
|
||||
form_device_type=request.form.get("device_type", ""),
|
||||
prefill_parent=parent_device), 400
|
||||
|
||||
if db.query(Device).filter_by(name=name).first():
|
||||
flash(f"A device named '{name}' already exists.", "error")
|
||||
@@ -706,19 +733,24 @@ def create_app(config_object="config"):
|
||||
device_battery_sizes=device_battery_sizes,
|
||||
form_name=name, form_slots=slots,
|
||||
form_notes=notes or "",
|
||||
form_device_type=request.form.get("device_type", "")), 400
|
||||
form_device_type=request.form.get("device_type", ""),
|
||||
prefill_parent=parent_device), 400
|
||||
|
||||
device = Device(name=name, battery_slots=slots, notes=notes,
|
||||
device_type=device_type, battery_size=battery_size,
|
||||
location=location)
|
||||
location=location,
|
||||
parent_id=parent_device.id if parent_device else None)
|
||||
db.add(device)
|
||||
db.commit()
|
||||
flash(f"Device '{name}' added.", "success")
|
||||
if parent_device:
|
||||
return redirect(url_for("device_detail", device_id=parent_device.id))
|
||||
return redirect(url_for("device_list"))
|
||||
|
||||
return render_template("device_add.html", device_types=device_types,
|
||||
device_locations=device_locations,
|
||||
device_battery_sizes=device_battery_sizes)
|
||||
device_battery_sizes=device_battery_sizes,
|
||||
prefill_parent=prefill_parent)
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Devices — detail
|
||||
@@ -767,6 +799,7 @@ def create_app(config_object="config"):
|
||||
device_types=device_types,
|
||||
device_locations=device_locations,
|
||||
device_battery_sizes=device_battery_sizes,
|
||||
device_list_all=all_devices,
|
||||
ha_enabled=ha_client.enabled,
|
||||
ha_live_pct=ha_live_pct,
|
||||
logbook_entries=device.logbook_entries)
|
||||
@@ -800,6 +833,23 @@ def create_app(config_object="config"):
|
||||
flash(f"A device named '{name}' already exists.", "error")
|
||||
return redirect(url_for("device_detail", device_id=device_id))
|
||||
|
||||
# Validate parent_id change
|
||||
parent_id_raw = request.form.get("parent_id", "").strip()
|
||||
if parent_id_raw and parent_id_raw.isdigit():
|
||||
new_parent = db.get(Device, int(parent_id_raw))
|
||||
if not new_parent:
|
||||
flash("Parent device not found.", "error")
|
||||
return redirect(url_for("device_detail", device_id=device_id))
|
||||
if new_parent.id == device_id:
|
||||
flash("A device cannot be its own parent.", "error")
|
||||
return redirect(url_for("device_detail", device_id=device_id))
|
||||
if new_parent.is_subcomponent():
|
||||
flash("Cannot nest sub-components more than one level deep.", "error")
|
||||
return redirect(url_for("device_detail", device_id=device_id))
|
||||
device.parent_id = new_parent.id
|
||||
else:
|
||||
device.parent_id = None
|
||||
|
||||
device.name = name
|
||||
device.battery_slots = slots
|
||||
device.notes = notes
|
||||
@@ -939,9 +989,15 @@ def create_app(config_object="config"):
|
||||
battery.status = "available"
|
||||
battery.device_id = None
|
||||
name = device.name
|
||||
child_names = [c.name for c in device.children]
|
||||
for child in device.children:
|
||||
child.parent_id = None
|
||||
db.delete(device)
|
||||
db.commit()
|
||||
flash(f"Device '{name}' deleted. All batteries marked available.", "success")
|
||||
msg = f"Device '{name}' deleted. All batteries marked available."
|
||||
if child_names:
|
||||
msg += f" Sub-components ({', '.join(child_names)}) are now independent devices."
|
||||
flash(msg, "success")
|
||||
return redirect(url_for("device_list"))
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
Reference in New Issue
Block a user