Replace LabelSelect with raw Select to fix MonsterUI value bug
MonsterUI LabelSelect has a confirmed bug where it sends the option's
label text instead of the value attribute on form submission. This was
causing 422 validation errors in forms.
- Replace all LabelSelect usages with raw Div(FormLabel, Select) pattern
- Add comments documenting the MonsterUI bug workaround
- Matches pattern already used in feed.py since commit ad1f910
Files modified: eggs.py, move.py, actions.py, products.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,6 @@ from monsterui.all import (
|
|||||||
ButtonT,
|
ButtonT,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
LabelInput,
|
LabelInput,
|
||||||
LabelSelect,
|
|
||||||
LabelTextArea,
|
LabelTextArea,
|
||||||
)
|
)
|
||||||
from ulid import ULID
|
from ulid import ULID
|
||||||
@@ -215,19 +214,17 @@ def cohort_form(
|
|||||||
H2("Create Animal Cohort", cls="text-xl font-bold mb-4"),
|
H2("Create Animal Cohort", cls="text-xl font-bold mb-4"),
|
||||||
# Error message if present
|
# Error message if present
|
||||||
error_component,
|
error_component,
|
||||||
# Species dropdown
|
# Species dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*species_options,
|
FormLabel("Species", _for="species"),
|
||||||
label="Species",
|
Select(*species_options, name="species", id="species", cls="uk-select"),
|
||||||
id="species",
|
cls="space-y-2",
|
||||||
name="species",
|
|
||||||
),
|
),
|
||||||
# Location dropdown
|
# Location dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*location_options,
|
FormLabel("Location", _for="location_id"),
|
||||||
label="Location",
|
Select(*location_options, name="location_id", id="location_id", cls="uk-select"),
|
||||||
id="location_id",
|
cls="space-y-2",
|
||||||
name="location_id",
|
|
||||||
),
|
),
|
||||||
# Count input
|
# Count input
|
||||||
LabelInput(
|
LabelInput(
|
||||||
@@ -239,26 +236,23 @@ def cohort_form(
|
|||||||
value=count_value,
|
value=count_value,
|
||||||
placeholder="Number of animals",
|
placeholder="Number of animals",
|
||||||
),
|
),
|
||||||
# Life stage dropdown
|
# Life stage dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*life_stage_options,
|
FormLabel("Life Stage", _for="life_stage"),
|
||||||
label="Life Stage",
|
Select(*life_stage_options, name="life_stage", id="life_stage", cls="uk-select"),
|
||||||
id="life_stage",
|
cls="space-y-2",
|
||||||
name="life_stage",
|
|
||||||
),
|
),
|
||||||
# Sex dropdown
|
# Sex dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*sex_options,
|
FormLabel("Sex", _for="sex"),
|
||||||
label="Sex",
|
Select(*sex_options, name="sex", id="sex", cls="uk-select"),
|
||||||
id="sex",
|
cls="space-y-2",
|
||||||
name="sex",
|
|
||||||
),
|
),
|
||||||
# Origin dropdown
|
# Origin dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*origin_options,
|
FormLabel("Origin", _for="origin"),
|
||||||
label="Origin",
|
Select(*origin_options, name="origin", id="origin", cls="uk-select"),
|
||||||
id="origin",
|
cls="space-y-2",
|
||||||
name="origin",
|
|
||||||
),
|
),
|
||||||
# Optional notes
|
# Optional notes
|
||||||
LabelTextArea(
|
LabelTextArea(
|
||||||
@@ -350,19 +344,17 @@ def hatch_form(
|
|||||||
H2("Record Hatch", cls="text-xl font-bold mb-4"),
|
H2("Record Hatch", cls="text-xl font-bold mb-4"),
|
||||||
# Error message if present
|
# Error message if present
|
||||||
error_component,
|
error_component,
|
||||||
# Species dropdown
|
# Species dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*species_options,
|
FormLabel("Species", _for="species"),
|
||||||
label="Species",
|
Select(*species_options, name="species", id="species", cls="uk-select"),
|
||||||
id="species",
|
cls="space-y-2",
|
||||||
name="species",
|
|
||||||
),
|
),
|
||||||
# Hatch location dropdown
|
# Hatch location dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*location_options,
|
FormLabel("Hatch Location", _for="location_id"),
|
||||||
label="Hatch Location",
|
Select(*location_options, name="location_id", id="location_id", cls="uk-select"),
|
||||||
id="location_id",
|
cls="space-y-2",
|
||||||
name="location_id",
|
|
||||||
),
|
),
|
||||||
# Hatched count input
|
# Hatched count input
|
||||||
LabelInput(
|
LabelInput(
|
||||||
@@ -374,13 +366,17 @@ def hatch_form(
|
|||||||
value=hatched_live_value,
|
value=hatched_live_value,
|
||||||
placeholder="Number hatched",
|
placeholder="Number hatched",
|
||||||
),
|
),
|
||||||
# Brood location dropdown (optional)
|
# Brood location dropdown (optional) - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
Div(
|
Div(
|
||||||
LabelSelect(
|
Div(
|
||||||
*brood_location_options,
|
FormLabel("Brood Location (optional)", _for="assigned_brood_location_id"),
|
||||||
label="Brood Location (optional)",
|
Select(
|
||||||
id="assigned_brood_location_id",
|
*brood_location_options,
|
||||||
name="assigned_brood_location_id",
|
name="assigned_brood_location_id",
|
||||||
|
id="assigned_brood_location_id",
|
||||||
|
cls="uk-select",
|
||||||
|
),
|
||||||
|
cls="space-y-2",
|
||||||
),
|
),
|
||||||
P(
|
P(
|
||||||
"If different from hatch location, hatchlings will be placed here",
|
"If different from hatch location, hatchlings will be placed here",
|
||||||
@@ -845,12 +841,11 @@ def tag_end_form(
|
|||||||
),
|
),
|
||||||
# Selection container - updated via HTMX when filter changes
|
# Selection container - updated via HTMX when filter changes
|
||||||
selection_container,
|
selection_container,
|
||||||
# Tag dropdown
|
# Tag dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*tag_options,
|
FormLabel("Tag to End", _for="tag"),
|
||||||
label="Tag to End",
|
Select(*tag_options, name="tag", id="tag", cls="uk-select"),
|
||||||
id="tag",
|
cls="space-y-2",
|
||||||
name="tag",
|
|
||||||
)
|
)
|
||||||
if active_tags
|
if active_tags
|
||||||
else Div(
|
else Div(
|
||||||
@@ -1318,20 +1313,22 @@ def outcome_form(
|
|||||||
yield_section = Div(
|
yield_section = Div(
|
||||||
H3("Yield Items", cls="text-lg font-semibold mt-4 mb-2"),
|
H3("Yield Items", cls="text-lg font-semibold mt-4 mb-2"),
|
||||||
P("Optional: record products collected from harvest", cls="text-sm text-stone-500 mb-3"),
|
P("Optional: record products collected from harvest", cls="text-sm text-stone-500 mb-3"),
|
||||||
|
# Using raw Select due to MonsterUI LabelSelect value bug
|
||||||
Div(
|
Div(
|
||||||
LabelSelect(
|
Div(
|
||||||
*product_options,
|
FormLabel("Product", _for="yield_product_code"),
|
||||||
label="Product",
|
Select(
|
||||||
id="yield_product_code",
|
*product_options,
|
||||||
name="yield_product_code",
|
name="yield_product_code",
|
||||||
cls="flex-1",
|
id="yield_product_code",
|
||||||
|
cls="uk-select",
|
||||||
|
),
|
||||||
|
cls="space-y-2 flex-1",
|
||||||
),
|
),
|
||||||
LabelSelect(
|
Div(
|
||||||
*unit_options,
|
FormLabel("Unit", _for="yield_unit"),
|
||||||
label="Unit",
|
Select(*unit_options, name="yield_unit", id="yield_unit", cls="uk-select"),
|
||||||
id="yield_unit",
|
cls="space-y-2 w-32",
|
||||||
name="yield_unit",
|
|
||||||
cls="w-32",
|
|
||||||
),
|
),
|
||||||
cls="flex gap-3",
|
cls="flex gap-3",
|
||||||
),
|
),
|
||||||
@@ -1377,13 +1374,11 @@ def outcome_form(
|
|||||||
),
|
),
|
||||||
# Selection container - updated via HTMX when filter changes
|
# Selection container - updated via HTMX when filter changes
|
||||||
selection_container,
|
selection_container,
|
||||||
# Outcome selection
|
# Outcome selection - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*outcome_options,
|
FormLabel("Outcome", _for="outcome"),
|
||||||
label="Outcome",
|
Select(*outcome_options, name="outcome", id="outcome", cls="uk-select", required=True),
|
||||||
id="outcome",
|
cls="space-y-2",
|
||||||
name="outcome",
|
|
||||||
required=True,
|
|
||||||
),
|
),
|
||||||
# Reason field
|
# Reason field
|
||||||
LabelInput(
|
LabelInput(
|
||||||
@@ -1599,13 +1594,13 @@ def status_correct_form(
|
|||||||
value=filter_str,
|
value=filter_str,
|
||||||
placeholder="e.g., species:duck location:Coop1",
|
placeholder="e.g., species:duck location:Coop1",
|
||||||
),
|
),
|
||||||
# New status selection
|
# New status selection - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*status_options,
|
FormLabel("New Status", _for="new_status"),
|
||||||
label="New Status",
|
Select(
|
||||||
id="new_status",
|
*status_options, name="new_status", id="new_status", cls="uk-select", required=True
|
||||||
name="new_status",
|
),
|
||||||
required=True,
|
cls="space-y-2",
|
||||||
),
|
),
|
||||||
# Reason field (required for admin actions)
|
# Reason field (required for admin actions)
|
||||||
LabelInput(
|
LabelInput(
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from fasthtml.common import H1, H2, A, Div, Form, Hidden, Li, Option, P, Ul
|
from fasthtml.common import H1, H2, A, Div, Form, Hidden, Li, Option, P, Select, Ul
|
||||||
from monsterui.all import (
|
from monsterui.all import (
|
||||||
Button,
|
Button,
|
||||||
ButtonT,
|
ButtonT,
|
||||||
|
FormLabel,
|
||||||
LabelInput,
|
LabelInput,
|
||||||
LabelSelect,
|
|
||||||
LabelTextArea,
|
LabelTextArea,
|
||||||
TabContainer,
|
TabContainer,
|
||||||
)
|
)
|
||||||
@@ -177,12 +177,11 @@ def harvest_form(
|
|||||||
H2("Harvest Eggs", cls="text-xl font-bold mb-4"),
|
H2("Harvest Eggs", cls="text-xl font-bold mb-4"),
|
||||||
# Error message if present
|
# Error message if present
|
||||||
error_component,
|
error_component,
|
||||||
# Location dropdown
|
# Location dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*location_options,
|
FormLabel("Location", _for="location_id"),
|
||||||
label="Location",
|
Select(*location_options, name="location_id", id="location_id", cls="uk-select"),
|
||||||
id="location_id",
|
cls="space-y-2",
|
||||||
name="location_id",
|
|
||||||
),
|
),
|
||||||
# Quantity input (integer only, 0 allowed for "checked but found none")
|
# Quantity input (integer only, 0 allowed for "checked but found none")
|
||||||
LabelInput(
|
LabelInput(
|
||||||
@@ -300,12 +299,11 @@ def sell_form(
|
|||||||
H2("Sell Products", cls="text-xl font-bold mb-4"),
|
H2("Sell Products", cls="text-xl font-bold mb-4"),
|
||||||
# Error message if present
|
# Error message if present
|
||||||
error_component,
|
error_component,
|
||||||
# Product dropdown
|
# Product dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*product_options,
|
FormLabel("Product", _for="product_code"),
|
||||||
label="Product",
|
Select(*product_options, name="product_code", id="product_code", cls="uk-select"),
|
||||||
id="product_code",
|
cls="space-y-2",
|
||||||
name="product_code",
|
|
||||||
),
|
),
|
||||||
# Quantity input (integer only, min=1)
|
# Quantity input (integer only, min=1)
|
||||||
LabelInput(
|
LabelInput(
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from fasthtml.common import H2, Div, Form, Hidden, Option, P, Span
|
from fasthtml.common import H2, Div, Form, Hidden, Option, P, Select, Span
|
||||||
from monsterui.all import Alert, AlertT, Button, ButtonT, LabelInput, LabelSelect, LabelTextArea
|
from monsterui.all import Alert, AlertT, Button, ButtonT, FormLabel, LabelInput, LabelTextArea
|
||||||
from ulid import ULID
|
from ulid import ULID
|
||||||
|
|
||||||
from animaltrack.models.events import Event
|
from animaltrack.models.events import Event
|
||||||
@@ -151,12 +151,11 @@ def move_form(
|
|||||||
),
|
),
|
||||||
# Selection container - updated via HTMX when filter changes
|
# Selection container - updated via HTMX when filter changes
|
||||||
selection_container,
|
selection_container,
|
||||||
# Destination dropdown
|
# Destination dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*location_options,
|
FormLabel("Destination", _for="to_location_id"),
|
||||||
label="Destination",
|
Select(*location_options, name="to_location_id", id="to_location_id", cls="uk-select"),
|
||||||
id="to_location_id",
|
cls="space-y-2",
|
||||||
name="to_location_id",
|
|
||||||
),
|
),
|
||||||
# Optional notes
|
# Optional notes
|
||||||
LabelTextArea(
|
LabelTextArea(
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from fasthtml.common import H2, Form, Hidden, Option
|
from fasthtml.common import H2, Div, Form, Hidden, Option, P, Select
|
||||||
from monsterui.all import Button, ButtonT, LabelInput, LabelSelect, LabelTextArea
|
from monsterui.all import Button, ButtonT, FormLabel, LabelInput, LabelTextArea
|
||||||
from ulid import ULID
|
from ulid import ULID
|
||||||
|
|
||||||
from animaltrack.models.reference import Product
|
from animaltrack.models.reference import Product
|
||||||
@@ -47,8 +47,6 @@ def product_sold_form(
|
|||||||
# Error display component
|
# Error display component
|
||||||
error_component = None
|
error_component = None
|
||||||
if error:
|
if error:
|
||||||
from fasthtml.common import Div, P
|
|
||||||
|
|
||||||
error_component = Div(
|
error_component = Div(
|
||||||
P(error, cls="text-red-500 text-sm"),
|
P(error, cls="text-red-500 text-sm"),
|
||||||
cls="mb-4",
|
cls="mb-4",
|
||||||
@@ -58,12 +56,11 @@ def product_sold_form(
|
|||||||
H2("Record Sale", cls="text-xl font-bold mb-4"),
|
H2("Record Sale", cls="text-xl font-bold mb-4"),
|
||||||
# Error message if present
|
# Error message if present
|
||||||
error_component,
|
error_component,
|
||||||
# Product dropdown
|
# Product dropdown - using raw Select due to MonsterUI LabelSelect value bug
|
||||||
LabelSelect(
|
Div(
|
||||||
*product_options,
|
FormLabel("Product", _for="product_code"),
|
||||||
label="Product",
|
Select(*product_options, name="product_code", id="product_code", cls="uk-select"),
|
||||||
id="product_code",
|
cls="space-y-2",
|
||||||
name="product_code",
|
|
||||||
),
|
),
|
||||||
# Quantity input (integer only, min=1)
|
# Quantity input (integer only, min=1)
|
||||||
LabelInput(
|
LabelInput(
|
||||||
|
|||||||
Reference in New Issue
Block a user