From 40769f5ce128fa52d9f68258b8c6e523eaf18ff2 Mon Sep 17 00:00:00 2001 From: Petru Paler Date: Thu, 1 Jan 2026 10:40:49 +0000 Subject: [PATCH] fix: add HTMX 422 response handling and missing form name attrs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Configure HTMX to swap 422 responses so validation errors display - Add missing name="notes" to egg harvest and product sold forms 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/animaltrack/web/app.py | 11 +++++++++-- src/animaltrack/web/templates/eggs.py | 1 + src/animaltrack/web/templates/products.py | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/animaltrack/web/app.py b/src/animaltrack/web/app.py index cdeaad2..f7cf781 100644 --- a/src/animaltrack/web/app.py +++ b/src/animaltrack/web/app.py @@ -5,7 +5,7 @@ from __future__ import annotations from pathlib import Path -from fasthtml.common import Beforeware, fast_app +from fasthtml.common import Beforeware, Meta, fast_app from monsterui.all import Theme from starlette.middleware import Middleware from starlette.requests import Request @@ -123,10 +123,17 @@ def create_app( # So static_path should be the parent of static_base static_path_for_fasthtml = str(static_base.parent) if static_base.exists() else "." + # Configure HTMX to swap 422 responses for validation errors + # Without this, hx-boost ignores non-2xx responses and errors appear to do nothing + htmx_config = Meta( + name="htmx-config", + content='{"responseHandling":[{"code":"204","swap":false},{"code":"[23]..","swap":true},{"code":"422","swap":true},{"code":"[45]..","swap":false,"error":true}]}', + ) + # Create FastHTML app with HTMX extensions, MonsterUI theme, and static path app, rt = fast_app( before=beforeware, - hdrs=Theme.slate.headers(), # Dark industrial theme + hdrs=(*Theme.slate.headers(), htmx_config), # Dark industrial theme + HTMX config exts=["head-support", "preload"], static_path=static_path_for_fasthtml, middleware=[Middleware(StaticCacheMiddleware)], diff --git a/src/animaltrack/web/templates/eggs.py b/src/animaltrack/web/templates/eggs.py index a9bf204..008b2c5 100644 --- a/src/animaltrack/web/templates/eggs.py +++ b/src/animaltrack/web/templates/eggs.py @@ -160,6 +160,7 @@ def harvest_form( LabelTextArea( "Notes", id="notes", + name="notes", placeholder="Optional notes", ), # Hidden nonce for idempotency diff --git a/src/animaltrack/web/templates/products.py b/src/animaltrack/web/templates/products.py index dddce60..f5033bc 100644 --- a/src/animaltrack/web/templates/products.py +++ b/src/animaltrack/web/templates/products.py @@ -99,6 +99,7 @@ def product_sold_form( LabelTextArea( "Notes", id="notes", + name="notes", placeholder="Optional notes", ), # Hidden nonce for idempotency