From 2d08061c45d85fb8106c5407489d0f04ccbb4e99 Mon Sep 17 00:00:00 2001 From: Donkie Date: Wed, 12 Aug 2026 20:25:00 +0200 Subject: [PATCH] client_v2: require the material when creating a filament MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Leaving Material blank sent you to Density instead. Density is only prefilled for a material Spoolman recognises, so a blank material surfaced as "Density is required" — an error on the field you didn't fill in because of the field you did miss, and inside the collapsed Advanced block at that. Material is now required on this form, so the error lands on the field that actually needs attention and Advanced stays shut. Typing a material we don't have specs for still asks for a density afterwards, which is the right order to be asked in. Client-side only: the API still accepts a filament with no material, so existing ones are unaffected. --- client_v2/src/lib/components/AddSpoolModal.svelte | 10 +++++++++- client_v2/src/lib/components/Combobox.svelte | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/client_v2/src/lib/components/AddSpoolModal.svelte b/client_v2/src/lib/components/AddSpoolModal.svelte index 66990882..35176164 100644 --- a/client_v2/src/lib/components/AddSpoolModal.svelte +++ b/client_v2/src/lib/components/AddSpoolModal.svelte @@ -500,6 +500,11 @@ // Mirrors the filament creation API (spoolman/api/v1/filament.py): // density & diameter are required and must be > 0; name/material ≤ 64 chars; // weight > 0, spool_weight/price ≥ 0; color_hex must be 6 or 8 hex chars. + // Material is the one field this form is stricter about than the API, which + // accepts a null one. Leaving it blank is nearly always an oversight, and it + // takes density down with it: density is only prefilled for a material we + // recognise, so a blank material surfaced as "Density is required" — an error + // on the field the user didn't fill in *because of* the field they did miss. function numErr( v: string, { required = false, min, max, gt }: { required?: boolean; min?: number; max?: number; gt?: number } = {} @@ -520,7 +525,8 @@ if (creating) { if (nf.name.trim().length === 0) e.name = m['validation.required'](); else if (nf.name.trim().length > 64) e.name = m['validation.maxChars']({ max: 64 }); - if (nf.material.trim().length > 64) e.material = m['validation.maxChars']({ max: 64 }); + if (nf.material.trim().length === 0) e.material = m['validation.required'](); + else if (nf.material.trim().length > 64) e.material = m['validation.maxChars']({ max: 64 }); if (nf.vendorName.trim().length > 64) e.vendor = m['validation.maxChars']({ max: 64 }); e.density = numErr(nf.density, { required: true, gt: 0 }); e.diameter = numErr(nf.diameter, { required: true, gt: 0 }); @@ -771,10 +777,12 @@