This commit is contained in:
Ross
2025-12-09 13:23:17 +00:00
parent ae52d80f98
commit dadc940993
2 changed files with 144 additions and 0 deletions
+3
View File
@@ -22,6 +22,9 @@ urlpatterns = [
path("rota/<int:rota_id>/export/builder/", views.rota_export_builder, name="rota_export_builder"),
path("rota/<int:rota_id>/options/update/", views.rota_options_update, name="rota_options_update"),
path("rota/<int:rota_id>/options/", views.rota_options, name="rota_options"),
path("rota/<int:rota_id>/option/add/", views.rota_option_add, name="rota_option_add"),
path("rota/<int:rota_id>/option/edit/", views.rota_option_edit, name="rota_option_edit"),
path("rota/<int:rota_id>/option/delete/", views.rota_option_delete, name="rota_option_delete"),
path("rota/<int:rota_id>/runs/clear/", views.rota_runs_clear, name="rota_runs_clear"),
path("run/<int:run_id>/export/regenerate/", views.rota_run_export_regenerate, name="rota_run_export_regenerate"),
]
+141
View File
@@ -335,6 +335,147 @@ def rota_options(request, rota_id):
return HttpResponse(modal_html)
def _oob_update_options_display(request, rota):
"""Helper: render options display and return HTMX OOB swap response."""
options_pretty = json.dumps(rota.options or {}, indent=4)
options_html = render_to_string(
"rota/partials/rota_options_display.html",
{"rota": rota, "options_pretty": options_pretty},
request=request,
)
resp = '<div id="rota-options-display" hx-swap-oob="true">' + options_html + '</div>' + '<div id="modal" hx-swap-oob="true"></div>'
response = HttpResponse(resp)
response["HX-Trigger"] = "closeModal"
return response
def rota_option_add(request, rota_id):
rota = get_object_or_404(RotaSchedule, pk=rota_id)
is_hx = request.headers.get("HX-Request", "false").lower() == "true"
if request.method == "POST":
key = request.POST.get("key", "").strip()
val = request.POST.get("value", "")
vtype = request.POST.get("type", "string")
if not key:
return HttpResponseBadRequest("Key is required")
# parse value according to type
try:
if vtype == "int":
parsed = int(val)
elif vtype == "float":
parsed = float(val)
elif vtype == "bool":
parsed = val.lower() in ("1", "true", "yes", "on")
elif vtype == "json":
parsed = json.loads(val) if val.strip() else None
else:
parsed = val
except Exception as exc:
return HttpResponseBadRequest(f"Invalid value: {exc}")
opts = rota.options or {}
opts[key] = parsed
rota.options = opts
rota.save(update_fields=["options"])
if is_hx:
return _oob_update_options_display(request, rota)
return redirect("rota:rota_detail", rota_id=rota.id)
# GET: show modal partial
modal_html = render_to_string(
"rota/partials/rota_option_modal_single.html",
{"form_action": reverse("rota:rota_option_add", args=(rota.id,)), "initial": {"key": "", "value": "", "type": "string"}, "rota": rota},
request=request,
)
return HttpResponse(modal_html)
def rota_option_edit(request, rota_id):
rota = get_object_or_404(RotaSchedule, pk=rota_id)
is_hx = request.headers.get("HX-Request", "false").lower() == "true"
if request.method == "POST":
key = request.POST.get("key", "").strip()
val = request.POST.get("value", "")
vtype = request.POST.get("type", "string")
if not key:
return HttpResponseBadRequest("Key is required")
try:
if vtype == "int":
parsed = int(val)
elif vtype == "float":
parsed = float(val)
elif vtype == "bool":
parsed = val.lower() in ("1", "true", "yes", "on")
elif vtype == "json":
parsed = json.loads(val) if val.strip() else None
else:
parsed = val
except Exception as exc:
return HttpResponseBadRequest(f"Invalid value: {exc}")
opts = rota.options or {}
opts[key] = parsed
rota.options = opts
rota.save(update_fields=["options"])
if is_hx:
return _oob_update_options_display(request, rota)
return redirect("rota:rota_detail", rota_id=rota.id)
# GET: prepare edit modal with existing value
key = request.GET.get("key")
if not key:
return HttpResponseBadRequest("Missing key")
current = rota.options or {}
cur_val = current.get(key, "")
# choose type hint
if isinstance(cur_val, bool):
vtype = "bool"
value = "1" if cur_val else "0"
elif isinstance(cur_val, int):
vtype = "int"
value = str(cur_val)
elif isinstance(cur_val, float):
vtype = "float"
value = str(cur_val)
elif isinstance(cur_val, (list, dict)):
vtype = "json"
value = json.dumps(cur_val)
else:
vtype = "string"
value = str(cur_val)
modal_html = render_to_string(
"rota/partials/rota_option_modal_single.html",
{"form_action": reverse("rota:rota_option_edit", args=(rota.id,)), "initial": {"key": key, "value": value, "type": vtype}, "rota": rota},
request=request,
)
return HttpResponse(modal_html)
@require_POST
def rota_option_delete(request, rota_id):
rota = get_object_or_404(RotaSchedule, pk=rota_id)
key = request.POST.get("key")
if not key:
return HttpResponseBadRequest("Missing key")
opts = rota.options or {}
if key in opts:
opts.pop(key)
rota.options = opts
rota.save(update_fields=["options"])
if request.headers.get("HX-Request", "false").lower() == "true":
return _oob_update_options_display(request, rota)
return redirect("rota:rota_detail", rota_id=rota.id)
def rota_run_export_download(request, run_id):
from .models import RotaRun