client_v2: don't link a missing manufacturer in the breadcrumbs

A filament with no vendor resolved through inventory.vendorOf(), whose
placeholder shows as "?" — rendered as a clickable crumb leading to a
broken vendor page. The inspectors now resolve the vendor directly and
fall back to a muted, non-navigable "No manufacturer" crumb, and drop
the "?" from the filament subtitle and spool title as well.

Claude-Session: https://claude.ai/code/session_014Cwk5Yyze9yPvkYkUtMAP4
This commit is contained in:
Donkie committed 2026-07-19 10:18:26 +02:00
1 parent 06eff55ccb
commit 5bd4fa594d
3 files changed
+27 -7

No files matched your search

@@ -1,10 +1,13 @@
<script lang="ts">
import ChevronRight from '@lucide/svelte/icons/chevron-right';
// Inspector breadcrumb trail. The last item is the current entity (rendered
// static); earlier items with an `onclick` are navigable.
// static); earlier items with an `onclick` are navigable. A `muted` crumb
// stands in for a level that doesn't exist (e.g. a filament with no
// manufacturer) — there's nothing to navigate to, so it reads as a note.
export interface Crumb {
label: string;
onclick?: () => void;
muted?: boolean;
}
let { items }: { items: Crumb[] } = $props();
</script>
@@ -14,6 +17,8 @@
{#if i > 0}<span class="sep"><ChevronRight size={13} /></span>{/if}
{#if c.onclick}
<button class="crumb" onclick={c.onclick}>{c.label}</button>
{:else if c.muted}
<span class="muted">{c.label}</span>
{:else}
<span class="current">{c.label}</span>
{/if}
@@ -43,4 +48,8 @@
.current {
color: var(--text-2);
}
.muted {
color: var(--text-dim);
font-style: italic;
}
</style>
@@ -28,7 +28,9 @@
let { filament }: { filament: Filament } = $props();
let vendor = $derived(inventory.vendorOf(filament));
// Undefined when the filament has no manufacturer set (or it isn't cached yet) —
// the display falls back to a plain "no manufacturer" note instead of a link.
let vendor = $derived(inventory.vendorById(filament.vendorId));
// Fetch this filament's spools from the API (scoped list) rather than the cache.
// Depend on the primitive id (via $derived) — not `filament` itself — so the
@@ -88,7 +90,9 @@
<div class="insp">
<Breadcrumbs
items={[
{ label: vendor.name, onclick: () => params.select('vendor', vendor.id) },
vendor
? { label: vendor.name, onclick: () => params.select('vendor', vendor.id) }
: { label: m['add.noManufacturer'](), muted: true },
{ label: filament.name }
]}
/>
@@ -103,7 +107,10 @@
title={serverInfo.externalDbName + ' · ' + filament.externalId}>{serverInfo.externalDbName}</span
>{/if}
</div>
<div class="subtitle">{vendor.name} · {filament.material} · {filament.diameter} mm</div>
<div class="subtitle">
{#if vendor}{vendor.name} ·
{/if}{filament.material} · {filament.diameter} mm
</div>
</div>
<div class="add">
<Button onclick={() => ui.openAddModal(filament.id)}
@@ -47,7 +47,9 @@
};
let filament = $derived(inventory.filamentById(spool.filamentId) ?? MISSING_FIL);
let vendor = $derived(inventory.vendorOf(filament));
// Undefined when the filament has no manufacturer set (or it isn't cached yet) —
// the display falls back to a plain "no manufacturer" note instead of a link.
let vendor = $derived(inventory.vendorById(filament.vendorId));
let used = $derived(spool.initial - spool.remaining);
// Existing locations for the location picker: pick an existing one from the
@@ -182,7 +184,9 @@
<div class="insp">
<Breadcrumbs
items={[
{ label: vendor.name, onclick: () => params.select('vendor', vendor.id) },
vendor
? { label: vendor.name, onclick: () => params.select('vendor', vendor.id) }
: { label: m['add.noManufacturer'](), muted: true },
{ label: filament.name, onclick: () => params.select('filament', filament.id) },
{ label: '#' + spool.id }
]}
@@ -192,7 +196,7 @@
<Swatch colors={filament.colors} size={40} radius={9} />
<div class="titles">
<div class="title">
{vendor.name}
{#if vendor}{vendor.name}{/if}
{filament.name}
<span class="idmono mono">#{spool.id}</span>
{#if spool.archived}<span class="arch-badge">{m['spool.fields.archived']()}</span>{/if}