You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
useIriLabels (lib/hooks/useIriLabels.ts) is type-agnostic: it resolves labels for arbitrary IRIs without knowing whether each one is a class, property, or individual. Its current strategy (after #200 / PR #104):
Primary: searchEntities by local name → returns label and type for any project entity
Fallback: getClassDetail → fires only when search returns no match
That fallback is the last source of console 404 noise. It fires for internal IRIs whose local name doesn't surface in the search index — typically opaque ID-style local names like RCBqIJm4IPngJgyvh49kP62. When such an IRI is in fact a property or individual, the class endpoint correctly returns 404; we catch the error silently, but Chrome still logs the 404.
The user-visible symptom (verified live):
GET /api/v1/projects/<id>/ontology/classes/https%3A%2F%2Fontology.catholicos.catholic%2FRCBqIJm4IPngJgyvh49kP62?branch=main
→ 404 (Not Found)
…repeating for every opaque-IRI'd property or individual referenced from the open panel. Functionally harmless; cosmetically bad.
Approach options
Option A — Per-IRI type hints from the caller (frontend-only)
Callsites already know the role of each IRI:
PropertyDetailPanel resolving parentIris → those are properties
PropertyDetailPanel resolving domainIris / rangeIris → those are classes
IndividualDetailPanel resolving typeIris → classes, sameAsIris → individuals, etc.
Change useIriLabels's API from (iris: string[], opts) to (entries: { iri: string; type?: SelectableEntityType }[], opts) (or three keyed lists). The hook routes each IRI to its specific endpoint when the type is known, falling through to search only when no hint is provided.
⚠ Every caller of useIriLabels needs updating (currently PropertyDetailPanel, IndividualDetailPanel, plus indirect callers)
⚠ "Mixed" IRI lists (e.g., a free-form annotation target) still need the search fallback
Option B — Parallel multi-type probes (frontend-only, no caller change)
When search misses, fire getClassDetail + getPropertyDetail + getIndividualDetail in parallel via Promise.allSettled, take the resolution that succeeds.
✅ No caller changes
❌ Doesn't reduce 404 noise — it just spreads it across three URL prefixes instead of one. Each parallel call to a non-matching endpoint still hits the network and logs 404.
Worth noting only to rule out.
Option C — Backend: single multi-type endpoint
Add GET /api/v1/projects/<id>/ontology/entities/<iri> returning { iri, type, labels, … } regardless of entity type. useIriLabels calls it as the only fallback.
✅ One call per IRI, zero 404s
✅ Lets us deprecate the search-by-local-name probe entirely if the endpoint is fast enough
⚠ Backend change required (ontokit-api), needs API design review and a migration plan
⚠ Fast-path performance vs. the existing per-type endpoints is unknown — a multi-type lookup may be slower than a typed one
Recommendation
A first, C eventually. Option A is contained, doesn't depend on the backend team, and gives correct routing immediately. The 1-3 callsites that pass mixed/free-form IRIs can keep the search fallback. If/when the API gains a multi-type endpoint (Option C), useIriLabels simplifies further but the caller-side type hints from Option A remain useful for documentation and short-circuit performance.
Confirm getPropertyDetail and getIndividualDetail exist with signatures parallel to getClassDetail. If they don't, add them (small backend-aware addition, but already needed by the detail panels themselves).
4. Tests
__tests__/lib/hooks/useIriLabels.test.ts — extend with cases:
Typed-property entry calls getPropertyDetail, never getClassDetail.
Typed-individual entry calls getIndividualDetail, never getClassDetail.
Untyped entry falls back to today's search-first behavior.
Mixed entry list (some typed, some untyped) routes correctly per entry.
PropertyDetailPanel.test.tsx and IndividualDetailPanel.test.tsx — assert that the right API methods are called when the panel resolves related-entity labels.
Done criteria
Opening any panel with internal property or individual IRIs in its rendered annotations / domain / range / parent / etc. produces zero 404s in the dev console.
Existing label resolution for class IRIs unaffected (regression coverage).
useIriLabels's untyped path still works for free-form annotation targets where the type is unknown.
Out of scope
Backend multi-type endpoint (Option C). Worth a separate ticket once Option A lands.
Reducing the search-first fallback further (already minimal noise with external-vocabulary skip + search-first ordering).
Problem
useIriLabels(lib/hooks/useIriLabels.ts) is type-agnostic: it resolves labels for arbitrary IRIs without knowing whether each one is a class, property, or individual. Its current strategy (after #200 / PR #104):searchEntitiesby local name → returns label and type for any project entitygetClassDetail→ fires only when search returns no matchThat fallback is the last source of console 404 noise. It fires for internal IRIs whose local name doesn't surface in the search index — typically opaque ID-style local names like
RCBqIJm4IPngJgyvh49kP62. When such an IRI is in fact a property or individual, the class endpoint correctly returns 404; we catch the error silently, but Chrome still logs the 404.The user-visible symptom (verified live):
…repeating for every opaque-IRI'd property or individual referenced from the open panel. Functionally harmless; cosmetically bad.
Approach options
Option A — Per-IRI type hints from the caller (frontend-only)
Callsites already know the role of each IRI:
PropertyDetailPanelresolvingparentIris→ those are propertiesPropertyDetailPanelresolvingdomainIris/rangeIris→ those are classesIndividualDetailPanelresolvingtypeIris→ classes,sameAsIris→ individuals, etc.Change
useIriLabels's API from(iris: string[], opts)to(entries: { iri: string; type?: SelectableEntityType }[], opts)(or three keyed lists). The hook routes each IRI to its specific endpoint when the type is known, falling through to search only when no hint is provided.SelectableEntityTypetype alias added in PR feat: preserve entity selection across viewer/editor modes #104 (lib/utils/selectionUrl.ts) is the natural shapeuseIriLabelsneeds updating (currentlyPropertyDetailPanel,IndividualDetailPanel, plus indirect callers)Option B — Parallel multi-type probes (frontend-only, no caller change)
When search misses, fire
getClassDetail+getPropertyDetail+getIndividualDetailin parallel viaPromise.allSettled, take the resolution that succeeds.Option C — Backend: single multi-type endpoint
Add
GET /api/v1/projects/<id>/ontology/entities/<iri>returning{ iri, type, labels, … }regardless of entity type.useIriLabelscalls it as the only fallback.Recommendation
A first, C eventually. Option A is contained, doesn't depend on the backend team, and gives correct routing immediately. The 1-3 callsites that pass mixed/free-form IRIs can keep the search fallback. If/when the API gains a multi-type endpoint (Option C),
useIriLabelssimplifies further but the caller-side type hints from Option A remain useful for documentation and short-circuit performance.Plan (Option A)
1. Reshape
useIriLabels's inputInternally:
typeis set: call the correspondinggetClassDetail/getPropertyDetail/getIndividualDetaildirectly. No fallback.typeis unset: keep today's search-first strategy (search → class fallback).2. Migrate callsites
components/editor/PropertyDetailPanel.tsx— pass typed entries forparentIris(property),domainIris/rangeIris(class),inverseOf(property), relationship targets (varies — keep untyped).components/editor/IndividualDetailPanel.tsx—typeIris(class),sameAsIris/differentFromIris(individual), object-property assertion subjects (typically class), data-property assertion targets (literal — skip).useIriLabelsaudited.3. Audit
projectOntologyApiConfirm
getPropertyDetailandgetIndividualDetailexist with signatures parallel togetClassDetail. If they don't, add them (small backend-aware addition, but already needed by the detail panels themselves).4. Tests
__tests__/lib/hooks/useIriLabels.test.ts— extend with cases:getPropertyDetail, nevergetClassDetail.getIndividualDetail, nevergetClassDetail.PropertyDetailPanel.test.tsxandIndividualDetailPanel.test.tsx— assert that the right API methods are called when the panel resolves related-entity labels.Done criteria
useIriLabels's untyped path still works for free-form annotation targets where the type is unknown.Out of scope
Related
react-hooks/set-state-in-effectcleanup; this issue is unrelated to that rule but improves the same overall code-quality pillar.SelectableEntityTypealias this proposal reuses.26bd907(external-vocabulary skip-list) andbc35651(search-first) on PR feat: preserve entity selection across viewer/editor modes #104 already reduced the 404 noise; this issue tracks closing it out.