Files
physicalCombinatorics/src/physcom_web/routes/entities.py
2026-07-25 16:42:39 -05:00

117 lines
4.3 KiB
Python

"""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("/<int:entity_id>", 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("/<int:entity_id>/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("/<int:entity_id>/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("/<int:entity_id>/deps/<int:dep_id>/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("/<int:entity_id>/deps/<int:dep_id>/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)