Commit 2dbb553c authored by Élodie Thiéblin's avatar Élodie Thiéblin
Browse files

feat(foaf): Add a foaf view using mui

Btw make eslint happy again
parent b7485443dddb
Pipeline #94381 passed with stages
in 5 minutes and 55 seconds
/* eslint-disable prettier/prettier */
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { SparqlView } from '@logilab/libview';
import { querySparql, sparqlResultToArray } from '@logilab/sparqlutils';
import { fetchUriAndLabels, generateUrlFunction, UriAndLabels } from './utils';
import { ListTextOrLink, TextOrLink, ListUris } from './SharedComponents';
import { Box, Card, CardContent, CardHeader, CardActions, Avatar, Chip, Container } from '@mui/material'
import { RowProperty, ChipsUris } from './SharedComponents';
import { Card, CardContent, CardHeader, Container } from '@mui/material';
import FaceIcon from '@mui/icons-material/Face';
import BookmarkIcon from '@mui/icons-material/Bookmark';
interface DublinCoreProps {
......@@ -20,33 +19,6 @@ interface DublinCoreProps {
subjects: UriAndLabels[];
}
const RowProperty: React.FC<{ name: string; uris: string[]; generateUrl: (uri: string) => string }> = ({
name,
uris,
generateUrl,
}) => {
if (uris.length === 0) {
return <></>;
} else if (uris.length === 1) {
return (
<>
<dt>{name}</dt>
<dd>
<TextOrLink str={uris[0]} generateUrl={generateUrl} />
</dd>
</>
);
}
return (
<>
<dt>{name}</dt>
<dd>
<ListTextOrLink items={uris} generateUrl={generateUrl} />
</dd>
</>
);
};
const DublinCoreComponent: React.FC<{ uri: string; endpoint: string; generateUrl: (uri: string) => string }> = ({
uri,
endpoint,
......@@ -61,9 +33,12 @@ const DublinCoreComponent: React.FC<{ uri: string; endpoint: string; generateUrl
<Card sx={{ marginTop: 10 }}>
<CardHeader title={titles[0]} />
<CardContent>
<Box sx={{justifyContent: "center", display: "flex", flexWrap: "wrap"}}>
{creators.map(({ uri, labels }) => <a key={uri} href={generateUrl(uri)}><Chip clickable={true} size="small" avatar={<Avatar><FaceIcon /></Avatar>} label={labels[0]?.value ?? "Missing label"} /> </a>)}
</Box>
<ChipsUris
relationName="Contributors"
urisAndLabels={creators}
generateUrl={generateUrl}
icon={<FaceIcon />}
/>
<dl>
<RowProperty name="Date" uris={dates} generateUrl={generateUrl} />
<RowProperty name="Description" uris={descriptions} generateUrl={generateUrl} />
......@@ -71,9 +46,12 @@ const DublinCoreComponent: React.FC<{ uri: string; endpoint: string; generateUrl
<RowProperty name="Has parts" uris={hasParts} generateUrl={generateUrl} />
<RowProperty name="Is part of" uris={isPartOf} generateUrl={generateUrl} />
</dl>
<Box>
{subjects.map(({uri, labels}) => <a key={uri} href={generateUrl(uri)}><Chip size="small" clickable={true} avatar={<Avatar><BookmarkIcon /></Avatar>} label={labels[0]?.value ?? uri} /> </a>)}
</Box>
<ChipsUris
relationName="Subjects"
urisAndLabels={subjects}
generateUrl={generateUrl}
icon={<BookmarkIcon />}
/>
</CardContent>
</Card>
</Container>
......
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { SparqlView } from '@logilab/libview';
import { querySparql, sparqlResultToArray } from '@logilab/sparqlutils';
import { generateUrlFunction, UriAndLabels, fetchUriAndLabels } from './utils';
import { Card, CardContent, CardHeader, Container } from '@mui/material';
import MenuBookIcon from '@mui/icons-material/MenuBook';
import { ListUris, RowProperty, ChipsUris } from './SharedComponents';
interface FoafProps {
names: string[];
givenNames: string[];
familyNames: string[];
sameAs: UriAndLabels[];
contributorOf: UriAndLabels[];
subjectOf: UriAndLabels[];
}
const FoafComponent: React.FC<{ uri: string; endpoint: string; generateUrl: (uri: string) => string }> = ({
uri,
endpoint,
generateUrl,
}) => {
const { names, givenNames, familyNames, sameAs, contributorOf, subjectOf } = useFoafData(uri, endpoint);
const displayedName =
names.length > 0
? names[0]
: givenNames.length > 0 || familyNames.length > 0
? `${givenNames[0] ?? ''} ${familyNames[0] ?? ''}`
: uri;
return (
<Container maxWidth="xs">
<Card sx={{ marginTop: 10 }}>
<CardHeader title={displayedName} />
<CardContent>
<dl>
<RowProperty name="Given names" uris={givenNames} generateUrl={generateUrl} />
<RowProperty name="Family names" uris={familyNames} generateUrl={generateUrl} />
</dl>
Equivalent to <ListUris uris={sameAs} generateUrl={generateUrl} />
<ChipsUris
relationName="Contributor of"
urisAndLabels={contributorOf}
generateUrl={generateUrl}
icon={<MenuBookIcon />}
/>
<ChipsUris
relationName="Subject of"
urisAndLabels={subjectOf}
generateUrl={generateUrl}
icon={<MenuBookIcon />}
/>
</CardContent>
</Card>
</Container>
);
};
const useFoafData = (uri: string, endpoint: string): FoafProps => {
const [names, setNames] = React.useState<string[]>([]);
const [familyNames, setFamilyNames] = React.useState<string[]>([]);
const [givenNames, setGivenNames] = React.useState<string[]>([]);
const [sameAs, setSameAs] = React.useState<UriAndLabels[]>([]);
const [contributorOf, setContributorOf] = React.useState<UriAndLabels[]>([]);
const [subjectOf, setSubjectOf] = React.useState<UriAndLabels[]>([]);
React.useEffect(() => {
async function fetchData() {
try {
const tempNames = new Set<string>();
const tempFamilyNames = new Set<string>();
const tempGivenNames = new Set<string>();
const tempSameAs = await fetchUriAndLabels(
endpoint,
`PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT DISTINCT ?uri ?label {
<${uri}> owl:sameAs ?uri
OPTIONAL{{?uri rdfs:label ?label.}
UNION
{?uri ?labelprop ?label.
?labelprop rdfs:subPropertyOf rdfs:label.}
}} ORDER BY ?label`
);
const tempContributorOf = await fetchUriAndLabels(
endpoint,
`PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT DISTINCT ?uri ?label {
{?uri dcterms:creator <${uri}>.}
UNION{?uri dc:creator <${uri}>.}
UNION{?uri dcterms:contributor <${uri}>.}
UNION{?uri dc:contributor <${uri}>.}
UNION{?uri ?rel <${uri}>. ?rel rdfs:subPropertyOf dc:contributor.}
UNION{?uri ?rel <${uri}>. ?rel rdfs:subPropertyOf dcterms:contributor.}
UNION{?uri ?rel <${uri}>. ?rel rdfs:subPropertyOf dc:creator.}
UNION{?uri ?rel <${uri}>. ?rel rdfs:subPropertyOf dcterms:creator.}
OPTIONAL{{?uri rdfs:label ?label.}
UNION
{?uri ?labelprop ?label.
?labelprop rdfs:subPropertyOf rdfs:label.}
}} ORDER BY ?label`
);
const tempSubjectOf = await fetchUriAndLabels(
endpoint,
`PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT DISTINCT ?uri ?label {
{?uri dcterms:subject <${uri}>.}
UNION{?uri dc:subject <${uri}>.}
UNION{?uri ?rel <${uri}>. ?rel rdfs:subPropertyOf dc:subject.}
UNION{?uri ?rel <${uri}>. ?rel rdfs:subPropertyOf dcterms:subject.}
OPTIONAL{{?uri rdfs:label ?label.}
UNION
{?uri ?labelprop ?label.
?labelprop rdfs:subPropertyOf rdfs:label.}
}} ORDER BY ?label`
);
const queryResults = await querySparql(
endpoint,
`PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT DISTINCT ?name ?familyName ?givenName
WHERE {
{<${uri}> foaf:name ?name} UNION
{<${uri}> foaf:familyName|foaf:lastName ?familyName;
foaf:givenName ?givenName
}
} `
);
sparqlResultToArray(queryResults).forEach((elem) => {
if (elem['name'] !== undefined) {
tempNames.add(elem['name'].value);
}
if (elem['familyName'] !== undefined) {
tempFamilyNames.add(elem['familyName'].value);
}
if (elem['givenName'] !== undefined) {
tempGivenNames.add(elem['givenName'].value);
}
});
setNames([...tempNames]);
setFamilyNames([...tempFamilyNames]);
setGivenNames([...tempGivenNames]);
setSameAs([...tempSameAs]);
setContributorOf([...tempContributorOf]);
setSubjectOf([...tempSubjectOf]);
} catch (e) {
console.error(e.message);
}
}
fetchData();
}, [endpoint, uri]);
return { names, givenNames, familyNames, sameAs, contributorOf, subjectOf };
};
export class FoafView implements SparqlView {
isApplicable = async (uri: string, endpoint: string) => {
const queryResult = await querySparql(
endpoint,
`PREFIX foaf: <http://xmlns.com/foaf/0.1/>
ASK { { <${uri}> foaf:name ?y} UNION {<${uri}> foaf:familyName ?z; foaf:givenName ?x. } }`
);
return queryResult.boolean;
};
renderSparql = (
domElement: HTMLElement,
uri: string,
endpoint: string,
options?: { generateUrl?: (uri: string) => string }
) => {
ReactDOM.render(
<FoafComponent endpoint={endpoint} uri={uri} generateUrl={generateUrlFunction(options)} />,
domElement
);
};
}
export const VIEW_ENTRYPOINT = new FoafView();
import * as React from 'react';
import { List, ListItem } from '@material-ui/core';
import { Box, Avatar, Chip, List, ListItem } from '@mui/material';
import { getBestLabel, Label, UriAndLabels, generateUrlType } from './utils';
......@@ -40,10 +40,64 @@ export const ListUris: React.FC<{ uris: UriAndLabels[]; generateUrl: generateUrl
return (
<List>
{uris.map(({ uri, labels }) => (
<ListItem>
<ListItem key={uri}>
<TextOrLink str={uri} labels={labels} generateUrl={generateUrl} key={uri} />
</ListItem>
))}
</List>
);
};
export const RowProperty: React.FC<{ name: string; uris: string[]; generateUrl: (uri: string) => string }> = ({
name,
uris,
generateUrl,
}) => {
if (uris.length === 0) {
return <></>;
} else if (uris.length === 1) {
return (
<>
<dt>{name}</dt>
<dd>
<TextOrLink str={uris[0]} generateUrl={generateUrl} />
</dd>
</>
);
}
return (
<>
<dt>{name}</dt>
<dd>
<ListTextOrLink items={uris} generateUrl={generateUrl} />
</dd>
</>
);
};
export const ChipsUris: React.FC<{
urisAndLabels: UriAndLabels[];
generateUrl: (uri: string) => string;
icon: JSX.Element;
relationName: string;
}> = ({ urisAndLabels, generateUrl, icon, relationName }) =>
urisAndLabels.length > 0 ? (
<>
{' '}
{relationName}
<Box sx={{ maxHeight: '300px', overflowY: 'scroll', overflowX: 'hidden' }}>
{urisAndLabels.map(({ uri, labels }) => (
<a key={uri} href={generateUrl(uri)}>
<Chip
size="small"
clickable={true}
avatar={<Avatar>{icon}</Avatar>}
label={labels[0]?.value ?? uri}
/>
</a>
))}
</Box>
</>
) : (
<></>
);
......@@ -9,6 +9,11 @@
"description": "Displays SKOS Concept-Scheme information",
"url": "{DOMAIN}/view_skosConceptScheme.js"
},
{
"name": "Foaf",
"description": "Displays basic Foaf information",
"url": "{DOMAIN}/view_foaf.js"
},
{
"name": "OWL Class",
"description": "Displays basic OWL Class information",
......
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Container, List, ListItem, ListItemText } from '@material-ui/core';
import { Container } from '@material-ui/core';
import { SparqlView } from '@logilab/libview';
import { querySparql, sparqlResultToArray } from '@logilab/sparqlutils';
......
......@@ -6,7 +6,8 @@ module.exports = {
dc: './src/DublinCoreView.tsx',
skosConcept: './src/SKOS/skosConcept.tsx',
skosConceptScheme: './src/SKOS/skosConceptScheme.tsx',
owlClass: './src/owlclass.tsx'
owlClass: './src/owlclass.tsx',
foaf: './src/FoafView.tsx',
},
mode: isProd ? 'production' : 'development',
output: {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment