.
This commit is contained in:
+114
-1
@@ -5,11 +5,14 @@ from .models import RotaSchedule, Worker
|
||||
from .forms import WorkerForm, LeaveForm, RotaScheduleForm
|
||||
from .services import run_rota_async
|
||||
from .forms import ShiftForm
|
||||
from .forms import RotaOptionsForm
|
||||
import json
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.template.loader import render_to_string
|
||||
from django.http import HttpResponse, HttpResponseBadRequest
|
||||
from django.views.decorators.http import require_POST
|
||||
from django.shortcuts import HttpResponseRedirect
|
||||
import traceback
|
||||
|
||||
|
||||
def index(request):
|
||||
@@ -19,6 +22,23 @@ def index(request):
|
||||
|
||||
def rota_detail(request, rota_id):
|
||||
rota = get_object_or_404(RotaSchedule, pk=rota_id)
|
||||
# Prepare options form and available builder constraint defaults
|
||||
options_form = RotaOptionsForm()
|
||||
available_constraints = {}
|
||||
try:
|
||||
# Try to import RotaBuilder to surface its default constraint options
|
||||
import importlib
|
||||
|
||||
mod = importlib.import_module("rota_generator.shifts")
|
||||
RotaBuilder = getattr(mod, "RotaBuilder")
|
||||
try:
|
||||
rb = RotaBuilder()
|
||||
available_constraints = getattr(rb, "constraint_options", {})
|
||||
except Exception:
|
||||
# fallback to class attribute if instantiation fails
|
||||
available_constraints = {}
|
||||
except Exception:
|
||||
available_constraints = {}
|
||||
if request.method == "POST":
|
||||
# trigger a background run
|
||||
generate_builder = request.POST.get("generate_builder") == "1"
|
||||
@@ -26,7 +46,18 @@ def rota_detail(request, rota_id):
|
||||
run = run_rota_async(rota.id, generate_builder=generate_builder, builder_solve=builder_solve)
|
||||
return redirect(reverse("rota:rota_run_detail", args=(run.id,)))
|
||||
|
||||
return render(request, "rota/rota_detail.html", {"rota": rota})
|
||||
# Prefill options form with existing rota.options JSON
|
||||
try:
|
||||
opt_json = json.dumps(rota.options or {}, indent=4)
|
||||
except Exception:
|
||||
opt_json = "{}"
|
||||
|
||||
options_form = RotaOptionsForm(initial={"options_json": opt_json})
|
||||
return render(
|
||||
request,
|
||||
"rota/rota_detail.html",
|
||||
{"rota": rota, "options_form": options_form, "available_constraints": available_constraints},
|
||||
)
|
||||
|
||||
|
||||
def rota_create(request):
|
||||
@@ -41,6 +72,19 @@ def rota_create(request):
|
||||
return render(request, "rota/rota_form.html", {"form": form})
|
||||
|
||||
|
||||
def rota_edit(request, rota_id):
|
||||
rota = get_object_or_404(RotaSchedule, pk=rota_id)
|
||||
if request.method == "POST":
|
||||
form = RotaScheduleForm(request.POST, instance=rota)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
return redirect("rota:rota_detail", rota_id=rota.id)
|
||||
else:
|
||||
form = RotaScheduleForm(instance=rota)
|
||||
|
||||
return render(request, "rota/rota_form.html", {"form": form, "editing": True})
|
||||
|
||||
|
||||
def worker_create(request):
|
||||
# Support both full-page and HTMX modal flows. If the request comes from
|
||||
# HTMX (header `HX-Request: true`) we return the modal partial so it can
|
||||
@@ -222,6 +266,75 @@ def rota_run_export_html(request, run_id):
|
||||
return render(request, "rota/rota_run_export.html", {"run": run})
|
||||
|
||||
|
||||
@require_POST
|
||||
def rota_options_update(request, rota_id):
|
||||
"""Update a rota's JSON `options` from a posted textarea `options_json`.
|
||||
|
||||
This endpoint expects a POST with `options_json` containing a JSON object.
|
||||
It validates JSON and saves it into `RotaSchedule.options`.
|
||||
"""
|
||||
rota = get_object_or_404(RotaSchedule, pk=rota_id)
|
||||
options_json = request.POST.get("options_json", "")
|
||||
try:
|
||||
parsed = json.loads(options_json) if options_json.strip() else {}
|
||||
except Exception as exc:
|
||||
return HttpResponseBadRequest(f"Invalid JSON: {exc}")
|
||||
|
||||
rota.options = parsed
|
||||
rota.save(update_fields=["options"])
|
||||
return redirect("rota:rota_detail", rota_id=rota.id)
|
||||
|
||||
|
||||
def rota_options(request, rota_id):
|
||||
"""HTMX-aware modal edit for rota.options JSON.
|
||||
|
||||
GET: return modal partial containing the JSON textarea form.
|
||||
POST: validate and save JSON; if HTMX, return OOB swap updating the options display and clear the modal.
|
||||
"""
|
||||
rota = get_object_or_404(RotaSchedule, pk=rota_id)
|
||||
is_hx = request.headers.get("HX-Request", "false").lower() == "true"
|
||||
|
||||
if request.method == "POST":
|
||||
options_json = request.POST.get("options_json", "")
|
||||
try:
|
||||
parsed = json.loads(options_json) if options_json.strip() else {}
|
||||
except Exception as exc:
|
||||
if is_hx:
|
||||
return HttpResponseBadRequest(f"Invalid JSON: {exc}")
|
||||
return HttpResponseBadRequest(f"Invalid JSON: {exc}")
|
||||
|
||||
rota.options = parsed
|
||||
rota.save(update_fields=["options"])
|
||||
|
||||
if is_hx:
|
||||
# render display snippet and send OOB swap to update it and clear modal
|
||||
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
|
||||
|
||||
return redirect(reverse("rota:rota_detail", args=(rota.id,)))
|
||||
|
||||
# GET: return modal partial
|
||||
try:
|
||||
initial = {"options_json": json.dumps(rota.options or {}, indent=4)}
|
||||
except Exception:
|
||||
initial = {"options_json": "{}"}
|
||||
|
||||
modal_html = render_to_string(
|
||||
"rota/partials/rota_options_modal.html",
|
||||
{"form_action": reverse("rota:rota_options", args=(rota.id,)), "initial": initial, "rota": rota},
|
||||
request=request,
|
||||
)
|
||||
return HttpResponse(modal_html)
|
||||
|
||||
|
||||
def rota_run_export_download(request, run_id):
|
||||
from .models import RotaRun
|
||||
|
||||
|
||||
Reference in New Issue
Block a user