Skip to content

Commit 6358a5d

Browse files
Jurij89Jurij Skornik
andauthored
fix(node-ui): align context graph label fallbacks (#611)
* fix(node-ui): align context graph label fallbacks * fix(node-ui): preserve path-style context graph labels --------- Co-authored-by: Jurij Skornik <jurij.skornik@gmail.com>
1 parent 42ef1df commit 6358a5d

8 files changed

Lines changed: 75 additions & 39 deletions

File tree

packages/node-ui/src/ui/hooks/useMemoryEntities.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useState, useEffect, useMemo, useRef, useCallback } from 'react';
22
import { authHeaders } from '../api.js';
33
import { useMemoryGraphEvents } from './useNodeEvents.js';
4+
import { MEMORY_LABEL_PREDICATES } from '../lib/memoryLabels.js';
45

56
export type TrustLevel = 'working' | 'shared' | 'verified';
67
export type MemoryLayerKey = 'wm' | 'swm' | 'vm';
@@ -48,13 +49,6 @@ export interface MemoryData {
4849
}
4950

5051
const RDF_TYPE = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
51-
const NAME_PREDS = [
52-
'http://schema.org/name',
53-
'http://www.w3.org/2000/01/rdf-schema#label',
54-
'http://purl.org/dc/terms/title',
55-
'http://purl.org/dc/elements/1.1/title',
56-
'http://xmlns.com/foaf/0.1/name',
57-
];
5852

5953
function bv(v: unknown): string | undefined {
6054
if (v == null) return undefined;
@@ -106,6 +100,10 @@ function isRawExtractionLabel(label: string, uri: string): boolean {
106100
return label === uri && /^urn:dkg:extraction:[^\s]+$/i.test(uri);
107101
}
108102

103+
function isUnreadableDefaultUriLabel(label: string, uri: string): boolean {
104+
return label === uri && (uri.startsWith('urn:') || uri.startsWith('did:'));
105+
}
106+
109107
function readableFallbackLabel(entity: MemoryEntity): string {
110108
const tail = readableTail(entity.uri);
111109
const type = entity.types
@@ -119,13 +117,18 @@ function readableFallbackLabel(entity: MemoryEntity): string {
119117
}
120118

121119
function deriveEntityLabel(entity: MemoryEntity): string {
122-
for (const pred of NAME_PREDS) {
120+
for (const pred of MEMORY_LABEL_PREDICATES) {
123121
const vals = entity.properties.get(pred);
124122
const name = vals?.find(v => v.trim().length > 0);
125123
if (name) return name;
126124
}
127125

128-
if (entity.label && !isRawExtractionLabel(entity.label, entity.uri)) {
126+
const defaultUriLabel = shortLabel(entity.uri);
127+
if (
128+
entity.label &&
129+
(entity.label !== defaultUriLabel || !isUnreadableDefaultUriLabel(entity.label, entity.uri)) &&
130+
!isRawExtractionLabel(entity.label, entity.uri)
131+
) {
129132
return entity.label;
130133
}
131134

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export const MEMORY_LABEL_PREDICATES = [
2+
'http://schema.org/name',
3+
'http://www.w3.org/2000/01/rdf-schema#label',
4+
'http://purl.org/dc/terms/title',
5+
'http://purl.org/dc/elements/1.1/title',
6+
'http://xmlns.com/foaf/0.1/name',
7+
] as const;
8+
9+
export function memoryGraphLabels(opts: {
10+
minZoomForLabels?: number;
11+
extraPredicates?: readonly string[];
12+
} = {}) {
13+
const labels: { predicates: string[]; minZoomForLabels?: number } = {
14+
predicates: [...(opts.extraPredicates ?? []), ...MEMORY_LABEL_PREDICATES],
15+
};
16+
if (opts.minZoomForLabels !== undefined) {
17+
labels.minZoomForLabels = opts.minZoomForLabels;
18+
}
19+
return labels;
20+
}

packages/node-ui/src/ui/views/MemoryLayerView.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useFetch } from '../hooks.js';
33
import { executeQuery, listAssertions, promoteAssertion, publishSharedMemory, listSwmEntities, type AssertionInfo, type PublishResult, type SwmRootEntity } from '../api.js';
44
import { FilePreviewModal } from '../components/Modals/FilePreviewModal.js';
55
import { useMemoryGraphEvents } from '../hooks/useNodeEvents.js';
6+
import { memoryGraphLabels } from '../lib/memoryLabels.js';
67

78
const RdfGraph = lazy(() =>
89
import('@origintrail-official/dkg-graph-viz/react').then(m => ({ default: m.RdfGraph }))
@@ -23,14 +24,7 @@ const LAYER_META: Record<MemoryLayer, { label: string; color: string; icon: stri
2324
const GRAPH_OPTIONS = {
2425
labelMode: 'humanized' as const,
2526
renderer: '2d' as const,
26-
labels: {
27-
predicates: [
28-
'http://schema.org/text',
29-
'http://schema.org/name',
30-
'http://www.w3.org/2000/01/rdf-schema#label',
31-
'http://purl.org/dc/terms/title',
32-
],
33-
},
27+
labels: memoryGraphLabels({ extraPredicates: ['http://schema.org/text'] }),
3428
style: {
3529
classColors: {
3630
'http://schema.org/Person': '#f472b6',

packages/node-ui/src/ui/views/project/components.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { ActivityFeed } from '../../components/ActivityFeed.js';
3030
import { VerifiedIdentityBanner } from '../../components/VerifiedIdentityBanner.js';
3131
import { SubGraphBar } from '../../components/SubGraphBar.js';
3232
import { GenUIEntityPanel } from '../../genui/index.js';
33+
import { memoryGraphLabels } from '../../lib/memoryLabels.js';
3334
import { useTabsStore } from '../../stores/tabs.js';
3435
import {
3536
useVerifiedMemoryAnchors,
@@ -2266,10 +2267,7 @@ export function KADetailView({ entity, allEntities, allTriples, onNavigate, onCl
22662267
const graphOptions = useMemo(() => ({
22672268
labelMode: 'humanized' as const,
22682269
renderer: '2d' as const,
2269-
labels: {
2270-
predicates: ['http://schema.org/name', 'http://www.w3.org/2000/01/rdf-schema#label'],
2271-
minZoomForLabels: 0.2,
2272-
},
2270+
labels: memoryGraphLabels({ minZoomForLabels: 0.2 }),
22732271
style: {
22742272
defaultNodeColor: TRUST_COLORS[entity.trustLevel],
22752273
defaultEdgeColor: '#475569',
@@ -2753,14 +2751,7 @@ export function SubGraphMiniCard({
27532751
const graphOptions = useMemo(() => ({
27542752
labelMode: 'humanized' as const,
27552753
renderer: '2d' as const,
2756-
labels: {
2757-
predicates: [
2758-
'http://schema.org/name',
2759-
'http://www.w3.org/2000/01/rdf-schema#label',
2760-
'http://purl.org/dc/terms/title',
2761-
],
2762-
minZoomForLabels: 0.8, // Keep labels out of the way in the mini view.
2763-
},
2754+
labels: memoryGraphLabels({ minZoomForLabels: 0.8 }), // Keep labels out of the way in the mini view.
27642755
style: {
27652756
classColors: CODE_CLASS_COLORS,
27662757
predicateColors: CODE_PREDICATE_COLORS,

packages/node-ui/src/ui/views/project/helpers.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
VIZ_ANCHOR_TYPE, VIZ_AGENT_TYPE,
1010
VIZ_PRED_ANCHORED_IN, VIZ_PRED_SIGNED_BY, VIZ_PRED_CONSENSUS,
1111
} from '../../hooks/useVerifiedMemoryAnchors.js';
12+
import { memoryGraphLabels } from '../../lib/memoryLabels.js';
1213

1314
export type LayerView = 'overview' | 'graph-overview' | 'query' | 'wm' | 'swm' | 'vm';
1415
export type LayerContentTab = 'items' | 'assertions' | 'graph' | 'docs';
@@ -234,14 +235,7 @@ export function buildLayerGraphOptions(
234235
return {
235236
labelMode: 'humanized' as const,
236237
renderer: '2d' as const,
237-
labels: {
238-
predicates: [
239-
'http://schema.org/name',
240-
'http://www.w3.org/2000/01/rdf-schema#label',
241-
'http://purl.org/dc/terms/title',
242-
],
243-
minZoomForLabels: isVM ? 0.2 : 0.3,
244-
},
238+
labels: memoryGraphLabels({ minZoomForLabels: isVM ? 0.2 : 0.3 }),
245239
style: {
246240
classColors: CODE_CLASS_COLORS,
247241
predicateColors: CODE_PREDICATE_COLORS,
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { MEMORY_LABEL_PREDICATES, memoryGraphLabels } from '../src/ui/lib/memoryLabels.js';
3+
import { buildLayerGraphOptions } from '../src/ui/views/project/helpers.js';
4+
5+
describe('graph label predicates', () => {
6+
it('builds graph label options from the shared predicate list', () => {
7+
expect(memoryGraphLabels({ minZoomForLabels: 0.4 })).toEqual({
8+
predicates: [...MEMORY_LABEL_PREDICATES],
9+
minZoomForLabels: 0.4,
10+
});
11+
12+
expect(memoryGraphLabels({ extraPredicates: ['http://schema.org/text'] }).predicates).toEqual([
13+
'http://schema.org/text',
14+
...MEMORY_LABEL_PREDICATES,
15+
]);
16+
});
17+
18+
it('uses the shared memory label predicate list for layer graphs', () => {
19+
const options = buildLayerGraphOptions('wm');
20+
21+
expect(options.labels.predicates).toEqual([...MEMORY_LABEL_PREDICATES]);
22+
expect(options.labels.predicates).toContain('http://purl.org/dc/elements/1.1/title');
23+
});
24+
});

packages/node-ui/test/ui-compat.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ describe('listAssertions query path', () => {
342342

343343
describe('useMemoryEntities hook', () => {
344344
const hook = readFileSync(resolve(UI_DIR, 'hooks', 'useMemoryEntities.ts'), 'utf-8');
345+
const memoryLabels = readFileSync(resolve(UI_DIR, 'lib', 'memoryLabels.ts'), 'utf-8');
345346
const nodeEventsHook = readFileSync(resolve(UI_DIR, 'hooks', 'useNodeEvents.ts'), 'utf-8');
346347

347348
it('exports TrustLevel type with three levels', () => {
@@ -372,8 +373,9 @@ describe('useMemoryEntities hook', () => {
372373
});
373374

374375
it('resolves entity labels from name predicates', () => {
375-
expect(hook).toContain('schema.org/name');
376-
expect(hook).toContain('rdf-schema#label');
376+
expect(hook).toContain('MEMORY_LABEL_PREDICATES');
377+
expect(memoryLabels).toContain('schema.org/name');
378+
expect(memoryLabels).toContain('rdf-schema#label');
377379
});
378380

379381
it('deduplicates triples across layers for graph data', () => {

packages/node-ui/test/use-memory-entities-labels.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ describe('useMemoryEntities readable labels', () => {
7373
binding('urn:test:named', SCHEMA_NAME, 'Friendly title', graph),
7474
binding('urn:test:source', RDF_TYPE, 'http://schema.org/Thing', graph),
7575
binding('urn:test:source', MENTIONS, extraction, graph),
76+
binding('urn:dkg:code:file:demo/project/src/file.ts', RDF_TYPE, 'http://dkg.io/ontology/code/File', graph),
77+
binding('did:dkg:agent:12D3KooWExample', RDF_TYPE, 'http://schema.org/Person', graph),
7678
];
7779
return {
7880
ok: true,
@@ -99,8 +101,14 @@ describe('useMemoryEntities readable labels', () => {
99101

100102
expect(el.getAttribute('data-loading')).toBe('false');
101103
expect(labels).toContain('urn:test:named=Friendly title');
104+
expect(labels).toContain('urn:test:source=source');
105+
expect(labels).toContain('urn:dkg:code:file:demo/project/src/file.ts=file.ts');
106+
expect(labels).toContain('did:dkg:agent:12D3KooWExample=Person 12D3KooWExample');
102107
expect(labels).toContain('urn:dkg:extraction:123e4567-e89b-12d3-a456-426614174000=Extraction 123e4567e89b');
103108
expect(labels).not.toContain('urn:dkg:extraction:123e4567-e89b-12d3-a456-426614174000=urn:dkg:extraction');
109+
expect(labels).not.toContain('urn:test:source=urn:test:source');
110+
expect(labels).not.toContain('urn:dkg:code:file:demo/project/src/file.ts=File file.ts');
111+
expect(labels).not.toContain('did:dkg:agent:12D3KooWExample=did:dkg:agent:12D3KooWExample');
104112
expect(targets).toContain('urn:dkg:extraction:123e4567-e89b-12d3-a456-426614174000=Extraction 123e4567e89b');
105113
});
106114
});

0 commit comments

Comments
 (0)