From 10ee09a5aac1d502fc4611431576ca1e14eb9cfa Mon Sep 17 00:00:00 2001 From: Kawa Date: Mon, 13 Apr 2026 10:50:27 +0200 Subject: [PATCH] fix(09-01): resolve driver upload 500 and add HTMX OOB refresh path - Import Form from fastapi for mixed multipart + form field support - Add caller: str = Form('') parameter to upload_driver handler - Capture new_driver from Driver.get_or_create() return tuple - Branch on caller == 'printer_form' to emit OOB-enabled response - Create partials/driver_upload_with_oob.html with primary driver_list include + hx-swap-oob select targeting id=printer-form-driver-select - New driver is auto-selected via new_driver_id context variable All 13 driver upload tests pass including 4 new OOB contract tests. Full non-e2e suite: 111 passed. --- imptune/api/drivers.py | 23 ++++++++++++++++--- .../partials/driver_upload_with_oob.html | 11 +++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 imptune/templates/partials/driver_upload_with_oob.html diff --git a/imptune/api/drivers.py b/imptune/api/drivers.py index 123a153..b8f154c 100644 --- a/imptune/api/drivers.py +++ b/imptune/api/drivers.py @@ -6,7 +6,7 @@ import json import zipfile from pathlib import Path -from fastapi import APIRouter, Request, UploadFile +from fastapi import APIRouter, Form, Request, UploadFile from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates @@ -33,7 +33,11 @@ def _error_response(message: str, status_code: int = 400) -> HTMLResponse: @router.post("/upload", response_class=HTMLResponse) -def upload_driver(request: Request, file: UploadFile) -> HTMLResponse: +def upload_driver( + request: Request, + file: UploadFile, + caller: str = Form(""), +) -> HTMLResponse: """Accept a driver ZIP, parse its INF, persist via DriverStore + Peewee ORM. Returns an HTMX partial (partials/driver_list.html) on success, or an @@ -86,7 +90,7 @@ def upload_driver(request: Request, file: UploadFile) -> HTMLResponse: sha256 = store.save(data) # Upsert Driver record (no duplicate if same SHA256) - Driver.get_or_create( + new_driver, _created = Driver.get_or_create( sha256=sha256, defaults={ "original_filename": filename, @@ -105,6 +109,19 @@ def upload_driver(request: Request, file: UploadFile) -> HTMLResponse: names = json.loads(d.driver_desc) if d.driver_desc else [] driver_data.append({"driver": d, "names": names}) + # When called from the printer form, emit primary fragment + OOB select refresh + if caller == "printer_form": + return templates.TemplateResponse( + request=request, + name="partials/driver_upload_with_oob.html", + context={ + "driver_data": driver_data, + "new_driver_id": new_driver.id, + "parsed": parsed, + }, + ) + + # Default: existing behavior — driver list fragment only return templates.TemplateResponse( request=request, name="partials/driver_list.html", diff --git a/imptune/templates/partials/driver_upload_with_oob.html b/imptune/templates/partials/driver_upload_with_oob.html new file mode 100644 index 0000000..3504c55 --- /dev/null +++ b/imptune/templates/partials/driver_upload_with_oob.html @@ -0,0 +1,11 @@ +{% include "partials/driver_list.html" %} + +