v0.1.19 - Throughput overview & responsive header
- Throughput: new "Throughput Overview" header with Gauge icon and brand-green badge icons on each card (Today, This week, 4-week average, Horse Mix, Grain Mix) - Throughput: inline rolling-range selector (7d / 4w / 6w / 12w, default 4 weeks) driving the customer-mix cards; stats window widened to 12 weeks so switching range is a pure client-side re-filter - Throughput: cards collapse to a single even 5-across row on laptop and up, with container-query value text that scales to each card's width - Throughput: date logic pinned to Australian Eastern time (fixes the day-early date); This week subtitle shows the Mon-Sun date range - Throughput: subtler tinted add-form; removed the inline-entry kicker and the "Open full form" link - Topbar: fix cramped laptop header - action toggles no longer wrap above the user button; search drops to its own row earlier Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
@@ -36,6 +38,52 @@ class EditorMixUpdate(BaseModel):
|
||||
client_name: str | None = Field(default=None, min_length=1, max_length=255)
|
||||
name: str | None = Field(default=None, min_length=1, max_length=255)
|
||||
notes: str | None = Field(default=None, max_length=2000)
|
||||
# Toggling a mix's status fans out to the visibility of every product under it.
|
||||
visible: bool | None = None
|
||||
|
||||
|
||||
class EditorMixRow(BaseModel):
|
||||
id: int
|
||||
tenant_id: str
|
||||
client_name: str
|
||||
name: str
|
||||
# A mix reads as "Active" when at least one of its products is visible.
|
||||
visible: bool
|
||||
product_count: int
|
||||
visible_product_count: int
|
||||
notes: str | None
|
||||
|
||||
|
||||
class EditorMixIngredientRead(BaseModel):
|
||||
id: int
|
||||
raw_material_id: int
|
||||
raw_material_name: str
|
||||
quantity_kg: float
|
||||
notes: str | None
|
||||
|
||||
|
||||
class EditorMixFormulaRead(BaseModel):
|
||||
id: int
|
||||
tenant_id: str
|
||||
client_name: str
|
||||
name: str
|
||||
ingredients: list[EditorMixIngredientRead]
|
||||
total_kg: float
|
||||
|
||||
|
||||
class EditorMixIngredientCreate(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
raw_material_id: int
|
||||
quantity_kg: float = Field(gt=0)
|
||||
notes: str | None = Field(default=None, max_length=1000)
|
||||
|
||||
|
||||
class EditorMixIngredientUpdate(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
quantity_kg: float | None = Field(default=None, gt=0)
|
||||
notes: str | None = Field(default=None, max_length=1000)
|
||||
|
||||
|
||||
class EditorProductIngredientCreate(BaseModel):
|
||||
@@ -71,3 +119,46 @@ class EditorProductFormulaRead(BaseModel):
|
||||
mix_name: str
|
||||
ingredients: list[EditorProductIngredientRead]
|
||||
total_kg: float
|
||||
|
||||
|
||||
# --- Ingredients (raw materials) catalogue -----------------------------------
|
||||
|
||||
|
||||
class EditorIngredientRow(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
supplier: str | None
|
||||
unit_of_measure: str
|
||||
kg_per_unit: float
|
||||
status: str
|
||||
# Decimal places this ingredient is rounded to in the mix calculator output.
|
||||
rounding_decimals: int
|
||||
notes: str | None
|
||||
cost_per_kg: float | None
|
||||
# How many product/mix formulas currently reference this ingredient.
|
||||
usage_count: int
|
||||
created_at: datetime
|
||||
|
||||
|
||||
class EditorIngredientCreate(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
name: str = Field(min_length=1, max_length=255)
|
||||
supplier: str | None = Field(default=None, max_length=255)
|
||||
unit_of_measure: str = Field(min_length=1, max_length=64)
|
||||
kg_per_unit: float = Field(gt=0)
|
||||
status: str = Field(default="active", max_length=32)
|
||||
rounding_decimals: int = Field(default=2, ge=0, le=6)
|
||||
notes: str | None = Field(default=None, max_length=2000)
|
||||
|
||||
|
||||
class EditorIngredientUpdate(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
name: str | None = Field(default=None, min_length=1, max_length=255)
|
||||
supplier: str | None = Field(default=None, max_length=255)
|
||||
unit_of_measure: str | None = Field(default=None, min_length=1, max_length=64)
|
||||
kg_per_unit: float | None = Field(default=None, gt=0)
|
||||
status: str | None = Field(default=None, max_length=32)
|
||||
rounding_decimals: int | None = Field(default=None, ge=0, le=6)
|
||||
notes: str | None = Field(default=None, max_length=2000)
|
||||
|
||||
Reference in New Issue
Block a user