Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RDFS Label functionality #77

Merged
merged 14 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions e2e/pages/settings/GeneralSettingsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { navigateTo } from '$e2e/helpers/navigation';

export default class GeneralSettingsPage extends LDExplorerPage {
readonly defaultLimitSetting: Locator;
readonly displayLabelsSetting: Locator;
readonly applyButton: Locator;

constructor(public readonly page: Page) {
super(page);
this.defaultLimitSetting = page.getByLabel('Default Limit');
this.displayLabelsSetting = page.getByText('Display Labels');
this.applyButton = page.getByRole('button', { name: 'Apply' });
}

Expand All @@ -26,4 +28,9 @@ export default class GeneralSettingsPage extends LDExplorerPage {
await this.defaultLimitSetting.fill(limit.toString());
await this.applyButton.click();
}

async toggleShowLabels() {
await this.displayLabelsSetting.click();
await this.applyButton.click();
}
}
46 changes: 0 additions & 46 deletions e2e/tests/features/settings/general-settings.test.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* (c) Crown Copyright GCHQ */

import { expect, test } from '$e2e/test';

test.describe('Default Limit setting', () => {
test.beforeEach(
async ({ sherlockExampleDataTTL, addLocalDataSourcePage, importToLocalDataSourcePage }) => {
const sourceName = 'Sherlock Data';
await addLocalDataSourcePage.goto();
await addLocalDataSourcePage.createLocalDataSource(sourceName);
await importToLocalDataSourcePage.navigateTo(sourceName);
await importToLocalDataSourcePage.importRdfData(sherlockExampleDataTTL);
}
);

test('Default limit of 1000 works as expected', async ({ exploreIndividualsPage }) => {
await exploreIndividualsPage.navigateTo();

// SPARQL indicator has correct limit
await exploreIndividualsPage.sparqlDetailToggle.click();
await expect(await exploreIndividualsPage.sparqlDetail).toContainText('LIMIT 1000');

// Table has two rows
await expect(exploreIndividualsPage.page.locator('table tbody tr')).toHaveCount(2);
});

test('Changing limit to 1 works as expected', async ({
exploreIndividualsPage,
generalSettingsPage
}) => {
await generalSettingsPage.navigateTo();
await generalSettingsPage.setDefaultLimit(1);

await exploreIndividualsPage.navigateTo();

// SPARQL indicator has correct limit
await exploreIndividualsPage.sparqlDetailToggle.click();
await expect(await exploreIndividualsPage.sparqlDetail).not.toContainText('LIMIT 1000');
await expect(await exploreIndividualsPage.sparqlDetail).toContainText('LIMIT 1');

// Table has two rows
await expect(exploreIndividualsPage.page.locator('table tbody tr')).toHaveCount(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* (c) Crown Copyright GCHQ */

import { expect, test } from '$e2e/test';

const sourceData = `
@prefix ex: <http://example.org/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

ex:team1 a ex:SportsTeam .
ex:team1 rdfs:label "E2E Testing Athletic FC" .
ex:SportsTeam rdfs:label "Sports Team" .`;

test.describe('Display Labels setting', () => {
test.beforeEach(async ({ addLocalDataSourcePage, importToLocalDataSourcePage }) => {
const sourceName = 'Test';
await addLocalDataSourcePage.goto();
await addLocalDataSourcePage.createLocalDataSource(sourceName);
await importToLocalDataSourcePage.navigateTo(sourceName);
await importToLocalDataSourcePage.importRdfData(sourceData);
});

test('Defaults to not labelling', async ({ page, exploreIndividualsPage }) => {
await exploreIndividualsPage.navigateTo();
await expect(
page.getByRole('link', {
name: 'http://example.org/team1',
exact: true
})
).toBeVisible();
await expect(
page.getByRole('link', {
name: 'http://example.org/SportsTeam',
exact: true
})
).toBeVisible();
});

test('When labelling switched on, labels are shown', async ({
page,
generalSettingsPage,
exploreIndividualsPage
}) => {
await generalSettingsPage.navigateTo();
await generalSettingsPage.toggleShowLabels();

await exploreIndividualsPage.navigateTo();
await expect(
page.getByRole('link', {
name: 'E2E Testing Athletic FC',
exact: true
})
).toBeVisible();
await expect(
page.getByRole('link', {
name: 'Sports Team',
exact: true
})
).toBeVisible();
});
});
17 changes: 12 additions & 5 deletions src/lib/components/ui/rdfjs/Term.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@
* for details; https://rdf.js.org/data-model-spec/#term-interface
*/
import { Link, QuotedTriple, TermValue } from '$lib/components';
import { type TermSettings, settings as savedSettings } from '$lib/stores/settings.store';
import { type Settings, settings as savedSettings } from '$lib/stores/settings.store';
import type { Term } from '@rdfjs/types';
import { abbreviateTermPrefix } from '$lib/util/term.utils';
import clsx from 'clsx';
import { prefixes } from '$lib/stores/prefixes.store';
import { labelFor } from '$stores/labelLookup.svelte';

// Props
interface Props {
applyVerticalMargins?: boolean;
term: Term;
settings?: TermSettings; // settings exposed as prop to allow for preview functionality
settings?: Settings; // settings exposed as prop to allow for preview functionality
highlightText?: string;
}

Expand All @@ -40,7 +41,7 @@
Quad: { colour: 'bg-lime-400', text: 'Quoted Triple' }
};

let termValue = $derived(
let termDisplayValue = $derived(
term.value && settings.term__abbreviateCommonPrefixes
? abbreviateTermPrefix(term.value || '', $prefixes)
: term.value
Expand All @@ -59,13 +60,19 @@
<QuotedTriple {term} />
{:else if term.termType == 'NamedNode'}
<Link href={`/explore/iris/detail?iri=${encodeURIComponent(term.value)}`}>
<TermValue {termValue} {highlightText} />
{#if settings.general__showRDFSLabels}
{#await labelFor(term.value, { defaultValue: termDisplayValue }) then label}
<TermValue termValue={label} {highlightText} />
{/await}
{:else}
<TermValue termValue={termDisplayValue} {highlightText} />
{/if}
</Link>
{:else}
{#if settings.term__showLanguageTag && term.termType == 'Literal' && term.language && term.language.length}
<span class="bg-gray-100 px-1">@{term.language}</span>
{/if}
<TermValue {termValue} {highlightText} />
<TermValue termValue={termDisplayValue} {highlightText} />
{/if}
</span>
</span>
Expand Down
57 changes: 57 additions & 0 deletions src/lib/data/labels.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type": "Type",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#Property": "Property",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement": "Statement",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#List": "List",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#subject": "Subject",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": "Predicate",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#object": "Object",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first": "First",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest": "Rest",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#value": "Value",
"http://www.w3.org/2000/01/rdf-schema#Resource": "Resource",
"http://www.w3.org/2000/01/rdf-schema#Class": "Class",
"http://www.w3.org/2000/01/rdf-schema#subClassOf": "Sub Class Of",
"http://www.w3.org/2000/01/rdf-schema#subPropertyOf": "Sub Property Of",
"http://www.w3.org/2000/01/rdf-schema#comment": "Comment",
"http://www.w3.org/2000/01/rdf-schema#label": "Label",
"http://www.w3.org/2000/01/rdf-schema#domain": "Domain",
"http://www.w3.org/2000/01/rdf-schema#range": "Range",
"http://www.w3.org/2000/01/rdf-schema#seeAlso": "See also",
"http://www.w3.org/2000/01/rdf-schema#isDefinedBy": "Is defined by",
"http://www.w3.org/2000/01/rdf-schema#Literal": "Literal",
"http://www.w3.org/2000/01/rdf-schema#Datatype": "Datatype",
"http://www.w3.org/2002/07/owl": "The OWL 2 Schema vocabulary (OWL 2)",
"http://www.w3.org/2002/07/owl#Class": "Class",
"http://www.w3.org/2002/07/owl#AllDifferent": "All Different",
"http://www.w3.org/2002/07/owl#AllDisjointClasses": "All Disjoint Classes",
"http://www.w3.org/2002/07/owl#AllDisjointProperties": "All Disjoint Properties",
"http://www.w3.org/2002/07/owl#Annotation": "Annotation",
"http://www.w3.org/2002/07/owl#AnnotationProperty": "Annotation Property",
"http://www.w3.org/2002/07/owl#AsymmetricProperty": "Asymmetric Property",
"http://www.w3.org/2002/07/owl#Axiom": "Axiom",
"http://www.w3.org/2002/07/owl#DataRange": "Data Range",
"http://www.w3.org/2002/07/owl#DatatypeProperty": "Datatype Property",
"http://www.w3.org/2002/07/owl#FunctionalProperty": "Functional Property",
"http://www.w3.org/2002/07/owl#InverseFunctionalProperty": "Inverse Functional Property",
"http://www.w3.org/2002/07/owl#Nothing": "Nothing",
"http://www.w3.org/2002/07/owl#ObjectProperty": "Object Property",
"http://www.w3.org/2002/07/owl#Ontology": "Ontology",
"http://www.w3.org/2002/07/owl#Restriction": "Restriction",
"http://www.w3.org/2002/07/owl#SymmetricProperty": "Symmetric Property",
"http://www.w3.org/2002/07/owl#Thing": "Thing",
"http://www.w3.org/2002/07/owl#TransitiveProperty": "Transitive Property",
"http://www.w3.org/2002/07/owl#allValuesFrom": "All Values From",
"http://www.w3.org/2002/07/owl#differentFrom": "Different From",
"http://www.w3.org/2002/07/owl#disjointUnionOf": "Disjoint Union Of",
"http://www.w3.org/2002/07/owl#disjointWith": "Disjoint With",
"http://www.w3.org/2002/07/owl#equivalentClass": "Equivalent Class",
"http://www.w3.org/2002/07/owl#equivalentProperty": "Equivalent Property",
"http://www.w3.org/2002/07/owl#intersectionOf": "Intersection Of",
"http://www.w3.org/2002/07/owl#inverseOf": "Inverse Of",
"http://www.w3.org/2002/07/owl#sameAs": "Same As",
"http://www.w3.org/2002/07/owl#someValuesFrom": "Some Values From",
"http://www.w3.org/2002/07/owl#unionOf": "Union Of",
"http://www.w3.org/2002/07/owl#versionIRI": "Version IRI",
"http://www.w3.org/2002/07/owl#versionInfo": "Version Info"
}
5 changes: 0 additions & 5 deletions src/lib/data/sources-catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@
"description": "The w3c-hosted RDFa vocab",
"url": "https://www.w3.org/ns/rdfa.ttl"
},
{
"name": "RDFs",
"description": "The w3c-hosted RDFS vocab",
"url": "https://www.w3.org/2000/01/rdf-schema"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This link no longer accepts requests.

},
{
"name": "PROV",
"description": "W3C recommended model for exchanging data provenance",
Expand Down
67 changes: 67 additions & 0 deletions src/lib/stores/labelLookup.svelte.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* (c) Crown Copyright GCHQ */

import { sources } from '$lib/stores/sources/local-sources.store';
import { labelFor, flushLookup } from './labelLookup.svelte';
import { importRdfDocument } from '$lib/util/source.util';
import { get } from 'svelte/store';
import { waitFor } from '@testing-library/svelte';

const document = `
@prefix ex: <http://example.org/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

ex:team1 a ex:SportsTeam .
ex:team2 a ex:SportsTeam .
ex:team1 rdfs:label "Unit Testing United FC" .
`;

describe(labelFor, () => {
beforeEach(() => {
sources.addSource({
id: '',
type: 'LOCAL',
n3Store: undefined,
name: 'Test source',
description: 'Test sorce description',
enabled: true
});
const source = get(sources)[0];
importRdfDocument(source, document);
});

afterEach(() => {
flushLookup();
});

it('contains some default labels', async () => {
expect(await labelFor('http://www.w3.org/1999/02/22-rdf-syntax-ns#type')).toEqual('Type');
});

it('echoes back the same IRI if no label found', async () => {
expect(await labelFor('http://example.org/team2')).toEqual('http://example.org/team2');
});

it('provides default value if given', async () => {
expect(await labelFor('http://example.org/team2', { defaultValue: 'Flobalob' })).toEqual(
'Flobalob'
);
});

it('lazily finds the label if it exists in the data source', async () => {
// As this function defaults to lazy, it won't find the label straight away.
expect(await labelFor('http://example.org/team1')).toEqual('http://example.org/team1');

// if we wait a little while though, it will eventually return the right label. This lazy functionality is
// the default by design: The lookup is inside a $state rune, so Svelte's reactivity
// will sort out updating the tempaltes once a label has been found.
await waitFor(async () =>
expect(await labelFor('http://example.org/team1')).toEqual('Unit Testing United FC')
);
});

it('eagerly finds the label when requested', async () => {
expect(await labelFor('http://example.org/team1', { lazy: false })).toEqual(
'Unit Testing United FC'
);
});
});
Loading