"""Entity + dependency CRUD routes.""" from __future__ import annotations from flask import Blueprint, flash, redirect, render_template, request, url_for from physcom.models.entity import Dependency, Entity from physcom_web.app import get_repo bp = Blueprint("entities", __name__, url_prefix="/entities") @bp.route("/") def entity_list(): repo = get_repo() entities = repo.list_entities() # Group by dimension grouped: dict[str, list[Entity]] = {} for e in entities: grouped.setdefault(e.dimension, []).append(e) return render_template("entities/list.html", grouped=grouped) @bp.route("/new", methods=["GET", "POST"]) def entity_new(): repo = get_repo() if request.method == "POST": dimension = request.form["dimension"].strip() name = request.form["name"].strip() description = request.form.get("description", "").strip() if not dimension or not name: flash("Dimension and name are required.", "error") return render_template("entities/form.html", entity=None, dimensions=repo.list_dimensions()) entity = Entity(name=name, dimension=dimension, description=description) repo.add_entity(entity) flash(f"Entity '{name}' added to '{dimension}'.", "success") return redirect(url_for("entities.entity_detail", entity_id=entity.id)) return render_template("entities/form.html", entity=None, dimensions=repo.list_dimensions()) @bp.route("/", methods=["GET", "POST"]) def entity_detail(entity_id: int): repo = get_repo() entity = repo.get_entity(entity_id) if not entity: flash("Entity not found.", "error") return redirect(url_for("entities.entity_list")) if request.method == "POST": name = request.form["name"].strip() description = request.form.get("description", "").strip() if not name: flash("Name is required.", "error") else: repo.update_entity(entity_id, name, description) flash(f"Entity '{name}' updated.", "success") entity = repo.get_entity(entity_id) return render_template("entities/detail.html", entity=entity) @bp.route("//delete", methods=["POST"]) def entity_delete(entity_id: int): repo = get_repo() entity = repo.get_entity(entity_id) if entity: repo.delete_entity(entity_id) flash(f"Entity '{entity.name}' deleted.", "success") return redirect(url_for("entities.entity_list")) # ── Dependency CRUD (HTMX partials) ───────────────────────── @bp.route("//deps/add", methods=["POST"]) def dep_add(entity_id: int): repo = get_repo() dep = Dependency( category=request.form["category"].strip(), key=request.form["key"].strip(), value=request.form["value"].strip(), unit=request.form.get("unit", "").strip() or None, constraint_type=request.form.get("constraint_type", "requires").strip(), ) if not dep.category or not dep.key or not dep.value: flash("Category, key, and value are required.", "error") else: repo.add_dependency(entity_id, dep) flash("Dependency added.", "success") entity = repo.get_entity(entity_id) return render_template("entities/_dep_table.html", entity=entity) @bp.route("//deps//edit", methods=["POST"]) def dep_edit(entity_id: int, dep_id: int): repo = get_repo() dep = Dependency( category=request.form["category"].strip(), key=request.form["key"].strip(), value=request.form["value"].strip(), unit=request.form.get("unit", "").strip() or None, constraint_type=request.form.get("constraint_type", "requires").strip(), ) repo.update_dependency(dep_id, dep) flash("Dependency updated.", "success") entity = repo.get_entity(entity_id) return render_template("entities/_dep_table.html", entity=entity) @bp.route("//deps//delete", methods=["POST"]) def dep_delete(entity_id: int, dep_id: int): repo = get_repo() repo.delete_dependency(dep_id) flash("Dependency deleted.", "success") entity = repo.get_entity(entity_id) return render_template("entities/_dep_table.html", entity=entity)