Skip to content

Commit 5277610

Browse files
committed
fix(ontology): repoint Browse tab from dead /api/ontology/public to live endpoints
fetchOntology() hit GET /api/ontology/public, which never existed (404). The backend exposes OWL classes/properties as two public read-only endpoints (/api/ontology/classes, /api/ontology/properties) — safe GETs bypass auth via mutations_only(). Fetch both in parallel, unwrap the StandardResponse envelope, and map the snake_case OwlClass/OwlProperty domain shapes onto the client model. Co-Authored-By: jjohare <github@thedreamlab.uk>
1 parent fbeefdc commit 5277610

1 file changed

Lines changed: 55 additions & 8 deletions

File tree

client/src/features/ontology/hooks/useOntologyStore.ts

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,45 @@ interface OntologyContributionState {
109109
reset: () => void;
110110
}
111111

112+
// Unwrap the backend StandardResponse envelope ({ success, data }) to the
113+
// inner array, tolerating endpoints that return a bare array.
114+
function unwrapData(body: unknown): any[] {
115+
if (Array.isArray(body)) return body;
116+
const data = (body as { data?: unknown })?.data;
117+
return Array.isArray(data) ? data : [];
118+
}
119+
120+
// Map the snake_case OwlClass domain shape onto the client OntologyClass model.
121+
// `label` is Option<String> server-side, so fall back to the IRI; `parent_classes`
122+
// is a Vec — the client tree only models a single parent, so take the first.
123+
function mapOwlClasses(raw: any[]): OntologyClass[] {
124+
return raw.map((c) => ({
125+
iri: String(c.iri),
126+
label: c.label || String(c.iri),
127+
parentClass: Array.isArray(c.parent_classes) ? c.parent_classes[0] : undefined,
128+
description: c.description ?? undefined,
129+
annotations: c.properties && typeof c.properties === 'object' ? c.properties : undefined,
130+
}));
131+
}
132+
133+
// Map the snake_case OwlProperty domain shape onto OntologyProperty. The server
134+
// enum is "ObjectProperty" | "DataProperty" | "AnnotationProperty"; domain/range
135+
// are Vecs collapsed to their first member for the contribution UI.
136+
function mapOwlProperties(raw: any[]): OntologyProperty[] {
137+
const typeMap: Record<string, OntologyProperty['propertyType']> = {
138+
ObjectProperty: 'object',
139+
DataProperty: 'data',
140+
AnnotationProperty: 'annotation',
141+
};
142+
return raw.map((p) => ({
143+
iri: String(p.iri),
144+
label: p.label || String(p.iri),
145+
domain: Array.isArray(p.domain) ? p.domain[0] : undefined,
146+
range: Array.isArray(p.range) ? p.range[0] : undefined,
147+
propertyType: typeMap[p.property_type] ?? 'object',
148+
}));
149+
}
150+
112151
// Build tree structure from flat class list
113152
function buildClassTree(classes: OntologyClass[]): OntologyTreeNode[] {
114153
const nodeMap = new Map<string, OntologyTreeNode>();
@@ -204,16 +243,24 @@ export const useOntologyContributionStore = create<OntologyContributionState>()(
204243
set({ loading: true, error: null });
205244

206245
try {
207-
const response = await fetch('/api/ontology/public');
208-
209-
if (!response.ok) {
210-
throw new Error(`Failed to fetch ontology: ${response.statusText}`);
246+
// The backend exposes OWL classes/properties as two public read-only
247+
// endpoints (safe GETs bypass auth via `mutations_only()`); there is no
248+
// combined `/public` route. Fetch both in parallel and map the
249+
// snake_case OwlClass/OwlProperty domain shapes onto the client model.
250+
const [classesRes, propertiesRes] = await Promise.all([
251+
fetch('/api/ontology/classes'),
252+
fetch('/api/ontology/properties'),
253+
]);
254+
255+
if (!classesRes.ok) {
256+
throw new Error(`Failed to fetch ontology classes: ${classesRes.statusText}`);
257+
}
258+
if (!propertiesRes.ok) {
259+
throw new Error(`Failed to fetch ontology properties: ${propertiesRes.statusText}`);
211260
}
212261

213-
const data = await response.json();
214-
215-
const classes: OntologyClass[] = data.classes || [];
216-
const properties: OntologyProperty[] = data.properties || [];
262+
const classes = mapOwlClasses(unwrapData(await classesRes.json()));
263+
const properties = mapOwlProperties(unwrapData(await propertiesRes.json()));
217264

218265
set({
219266
classes,

0 commit comments

Comments
 (0)