Add manufacturer catalog, category/manufacturer library management, and built-in cable flag

Normalizes manufacturer as a shared catalog entity (like device categories)
instead of free text on each device, giving the admin duplicate-detection
nudge a reliable signal. Adds full CRUD (including Admin direct-publish,
bypassing the submission queue) for categories, manufacturers, port types,
and cable types, plus a Categories & Manufacturers library modal and a
browse-by-manufacturer/search view in the device palette. Adds
Port.builtInCable so a captive/permanently-attached cable (a keyboard's USB
lead, a budget AVR's power cord) can be flagged and excluded from the BOM.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017DUU6CnxECCDeqDNYJgr5x
This commit is contained in:
2026-09-28 10:04:05 -05:00
co-authored by Claude Sonnet 5
parent 00777077c2
commit 29c3ed46a3
28 changed files with 2201 additions and 320 deletions
+8 -1
View File
@@ -11,13 +11,20 @@ export default function CategorySelect({
value,
onChange,
className = 'mt-1 w-full rounded border border-slate-300 px-2 py-1 text-sm',
publishPublic = false,
}: {
value: string
onChange: (categoryId: string) => void
className?: string
/** When true, a category created here goes straight into the public
* catalog (Admin-only) instead of your own private one — used when the
* containing form is itself publishing directly, so a brand-new category
* it references doesn't end up private and invisible to everyone else. */
publishPublic?: boolean
}) {
const catalog = useCatalogStore((s) => s.catalog)
const addCustomDeviceCategory = useCatalogStore((s) => s.addCustomDeviceCategory)
const adminAddDeviceCategory = useCatalogStore((s) => s.adminAddDeviceCategory)
const [creating, setCreating] = useState(false)
const [draftName, setDraftName] = useState('')
@@ -29,7 +36,7 @@ export default function CategorySelect({
const commitNewCategory = async () => {
const trimmed = draftName.trim()
if (trimmed) {
onChange(await addCustomDeviceCategory(trimmed))
onChange(await (publishPublic ? adminAddDeviceCategory(trimmed) : addCustomDeviceCategory(trimmed)))
}
setCreating(false)
setDraftName('')