Problem
A node's detail panel shows external links as buttons labelled by the predicate that produced them: `↗ page` for `foaf:page` and `↗ seeAlso` for every `rdfs:seeAlso`. When a node has three or four `rdfs:seeAlso` links, the user sees:
```
↗ seeAlso
↗ seeAlso
↗ seeAlso
```
…with no visible information about what each link points to. They have to hover to see the URL or click blindly. This is a real readability problem now that data repositories (e.g. `lambdasistemi/cardano-knowledge-maps`) attach multiple authoritative references per node — official site + docs + repo + spec PR + project tracker is normal.
Where the labels come from
`src/Rdf/Import.purs::namedLink`:
```purescript
namedLink quads predicate url =
if isAbsoluteIri url then
Just
{ label: fromMaybe (decodeVocabularySuffix "" predicate) (literalValue quads predicate rdfsLabel)
, url
}
```
The label is taken from the predicate's `rdfs:label` (which `foaf:page` and `rdfs:seeAlso` don't carry locally), then falls back to the URI suffix of the predicate — yielding `"page"` and `"seeAlso"` respectively for every link of those types.
Proposed fix — two layers
Layer 1 (default): derive a useful label from the URL
When no per-predicate or per-link override applies, derive the label from the URL's hostname, stripping a leading `www.` and the trailing TLD where it adds noise. Examples of what the user would see instead:
This is a small change to `namedLink` plus a new helper that parses the URL and returns the host. It needs no data changes in any downstream repo and it covers ~90% of the legibility problem on day one.
Layer 2 (override): allow data to set a custom label
For the cases where a hostname isn't enough ("the proposal page" vs "the team's project tracker" — both at `milestones.projectcatalyst.io`), let data attach an explicit label via RDF Statement reification, mirroring the pattern that already works for edge descriptions:
```turtle
n:org-serviceplan-group rdfs:seeAlso https://milestones.projectcatalyst.io/projects/1300132 .
[] a rdf:Statement ;
rdf:subject n:org-serviceplan-group ;
rdf:predicate rdfs:seeAlso ;
rdf:object https://milestones.projectcatalyst.io/projects/1300132 ;
rdfs:label "Catalyst Fund 13 — Masumi (complete)" .
```
`namedLink` would look up that reified-statement label, falling back to Layer 1 when none is set.
Rejected alternative
Adding per-link predicates (`cardano:officialSite`, `cardano:docsSite`, `cardano:codeRepo`) was considered but rejected: `fallbackLinks` only recognises `foaf:page` and `rdfs:seeAlso`, so any new predicate would need importer changes anyway, and every data repo would need a vocabulary expansion. Layer 1 + Layer 2 above keep the data-side conventions stable.
Touch points
- `src/Rdf/Import.purs` — `namedLink` and a new `hostnameLabel :: String -> String`
- `src/Rdf/Import.purs` — extend the `rdf:Statement` lookup currently used for edge descriptions to also cover link labels (`(subject, rdfs:seeAlso, object)` triple keys)
- Optional: a small CSS tweak so longer hostnames don't blow up the link-button width
Downstream
`lambdasistemi/cardano-knowledge-maps` PR #47 just landed 355 external links across the Budget 2026 nodes; right now they all collapse to `page` / `seeAlso`. This fix is what makes that PR's investment readable.
Test plan
Release plan
This is additive on the data side (no schema change). It needs a graph-browser version bump. Will land as a feature commit on `main` then ride out the next release-please tag, after which data repos can pin to it.
Problem
A node's detail panel shows external links as buttons labelled by the predicate that produced them: `↗ page` for `foaf:page` and `↗ seeAlso` for every `rdfs:seeAlso`. When a node has three or four `rdfs:seeAlso` links, the user sees:
```
↗ seeAlso
↗ seeAlso
↗ seeAlso
```
…with no visible information about what each link points to. They have to hover to see the URL or click blindly. This is a real readability problem now that data repositories (e.g. `lambdasistemi/cardano-knowledge-maps`) attach multiple authoritative references per node — official site + docs + repo + spec PR + project tracker is normal.
Where the labels come from
`src/Rdf/Import.purs::namedLink`:
```purescript
namedLink quads predicate url =
if isAbsoluteIri url then
Just
{ label: fromMaybe (decodeVocabularySuffix "" predicate) (literalValue quads predicate rdfsLabel)
, url
}
```
The label is taken from the predicate's `rdfs:label` (which `foaf:page` and `rdfs:seeAlso` don't carry locally), then falls back to the URI suffix of the predicate — yielding `"page"` and `"seeAlso"` respectively for every link of those types.
Proposed fix — two layers
Layer 1 (default): derive a useful label from the URL
When no per-predicate or per-link override applies, derive the label from the URL's hostname, stripping a leading `www.` and the trailing TLD where it adds noise. Examples of what the user would see instead:
This is a small change to `namedLink` plus a new helper that parses the URL and returns the host. It needs no data changes in any downstream repo and it covers ~90% of the legibility problem on day one.
Layer 2 (override): allow data to set a custom label
For the cases where a hostname isn't enough ("the proposal page" vs "the team's project tracker" — both at `milestones.projectcatalyst.io`), let data attach an explicit label via RDF Statement reification, mirroring the pattern that already works for edge descriptions:
```turtle
n:org-serviceplan-group rdfs:seeAlso https://milestones.projectcatalyst.io/projects/1300132 .
[] a rdf:Statement ;
rdf:subject n:org-serviceplan-group ;
rdf:predicate rdfs:seeAlso ;
rdf:object https://milestones.projectcatalyst.io/projects/1300132 ;
rdfs:label "Catalyst Fund 13 — Masumi (complete)" .
```
`namedLink` would look up that reified-statement label, falling back to Layer 1 when none is set.
Rejected alternative
Adding per-link predicates (`cardano:officialSite`, `cardano:docsSite`, `cardano:codeRepo`) was considered but rejected: `fallbackLinks` only recognises `foaf:page` and `rdfs:seeAlso`, so any new predicate would need importer changes anyway, and every data repo would need a vocabulary expansion. Layer 1 + Layer 2 above keep the data-side conventions stable.
Touch points
Downstream
`lambdasistemi/cardano-knowledge-maps` PR #47 just landed 355 external links across the Budget 2026 nodes; right now they all collapse to `page` / `seeAlso`. This fix is what makes that PR's investment readable.
Test plan
Release plan
This is additive on the data side (no schema change). It needs a graph-browser version bump. Will land as a feature commit on `main` then ride out the next release-please tag, after which data repos can pin to it.