Skip to content

Commit cba86d6

Browse files
committed
fix(ui): add entity type prefix to convertToRelativeUrl for proper routing
Search results and other views using convertToRelativeUrl were generating URLs like #/T10211 instead of #/topics/T10211, causing navigation failures. - Add entity type detection from OpenAlex ID prefixes (W, A, T, etc.) - Handle both path-based URLs (topics/T10211) and bare IDs (T10211) - Map all OpenAlex prefixes including deprecated V (venues -> sources)
1 parent be89670 commit cba86d6

File tree

1 file changed

+46
-4
lines changed

1 file changed

+46
-4
lines changed

packages/ui/src/components/entity-views/matchers/entity-matchers.ts

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Matcher utilities for entity views
2-
import type { OpenAlexEntity } from "@bibgraph/types";
2+
import type { EntityType, OpenAlexEntity } from "@bibgraph/types";
33
import type { ComponentType } from "react";
44

55
export interface EntityMatcher {
@@ -29,12 +29,54 @@ export const defaultMatchers: EntityMatcher[] = [
2929
];
3030

3131
/**
32-
* Converts an OpenAlex URL or ID to a relative URL path
32+
* Map of OpenAlex ID prefixes to entity types
33+
*/
34+
const OPENALEX_PREFIX_TO_ENTITY_TYPE: Record<string, EntityType> = {
35+
W: "works",
36+
A: "authors",
37+
S: "sources",
38+
I: "institutions",
39+
P: "publishers",
40+
C: "concepts",
41+
F: "funders",
42+
T: "topics",
43+
K: "keywords",
44+
V: "sources", // Venues (deprecated, now sources)
45+
};
46+
47+
/**
48+
* Extracts the entity type from an OpenAlex ID prefix
49+
* @param id - OpenAlex ID (e.g., "W1234567890", "T10211")
50+
* @returns EntityType or null if not recognized
51+
*/
52+
const getEntityTypeFromIdPrefix = (id: string): EntityType | null => {
53+
const prefix = id.charAt(0).toUpperCase();
54+
return OPENALEX_PREFIX_TO_ENTITY_TYPE[prefix] ?? null;
55+
};
56+
57+
/**
58+
* Converts an OpenAlex URL or ID to a relative URL path with proper entity type prefix
3359
* @param urlOrId - Either a full OpenAlex URL (https://openalex.org/A123) or just an ID (A123)
34-
* @returns A hash-based relative URL (e.g., #/A123)
60+
* @returns A hash-based relative URL with entity type (e.g., #/authors/A123, #/topics/T10211)
3561
*/
3662
export const convertToRelativeUrl = (urlOrId: string): string => {
3763
// Extract just the ID part if it's a full URL
38-
const id = urlOrId.replace(/^https?:\/\/[^/]+\//, '');
64+
// Handle both direct ID URLs (openalex.org/T10211) and path-based URLs (openalex.org/topics/T10211)
65+
let id = urlOrId.replace(/^https?:\/\/(?:api\.)?openalex\.org\//, '');
66+
67+
// If the ID already includes an entity type path (e.g., "topics/T10211", "keywords/machine-learning"),
68+
// return it directly
69+
const pathBasedPattern = /^(works|authors|sources|institutions|topics|publishers|funders|concepts|fields|domains|subfields|keywords)\//i;
70+
if (pathBasedPattern.test(id)) {
71+
return `#/${id}`;
72+
}
73+
74+
// For bare IDs like "T10211" or "W1234567890", detect entity type from prefix
75+
const entityType = getEntityTypeFromIdPrefix(id);
76+
if (entityType) {
77+
return `#/${entityType}/${id}`;
78+
}
79+
80+
// Fallback: return as-is (shouldn't happen for valid OpenAlex IDs)
3981
return `#/${id}`;
4082
};

0 commit comments

Comments
 (0)