.
This commit is contained in:
@@ -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>/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/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>/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("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"),
|
path("run/<int:run_id>/export/regenerate/", views.rota_run_export_regenerate, name="rota_run_export_regenerate"),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -335,6 +335,147 @@ def rota_options(request, rota_id):
|
|||||||
return HttpResponse(modal_html)
|
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):
|
def rota_run_export_download(request, run_id):
|
||||||
from .models import RotaRun
|
from .models import RotaRun
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user