diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..a9bb80a --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,27 @@ +name: build.yml +on: + push: + branches: + - main + pull_request: + branches: + - main +jobs: + build: + runs-on: ubuntu-latest + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v7 + - name: Use Node.js + uses: actions/setup-node@v7 + with: + node-version: "24.x" + cache: "npm" + - name: Install + run: npm ci --ignore-scripts + - name: Prettier Check + run: npm run prettier:check + - name: Build + run: npm run-script build + env: + CI: "" diff --git a/src/api/TermAPI.ts b/src/api/TermAPI.ts index a4b2e5e..0e64fab 100644 --- a/src/api/TermAPI.ts +++ b/src/api/TermAPI.ts @@ -3,12 +3,15 @@ import { useQuery } from "react-query"; import { getPropertyRelationsQuery, getTermRelationsQuery, + getTermSkosRelationsQuery, getTermTypeQuery, TermBaseInterface, TermInterface, TermRelationsInterface, Terms, + TermSkosRelationsInterface, TermsRelationsResource, + TermsSkosRelationsResource, TermsTypes, } from "./data/terms"; import { HIDDEN_VOCABULARY } from "./data/vocabularies"; @@ -56,6 +59,17 @@ export const getRelations = async ( } }; +export const getSkosRelations = async ( + term: TermInterface | undefined +): Promise => { + if (typeof term === "undefined") { + return Promise.reject("Invalid term"); + } + return await TermsSkosRelationsResource.query( + getTermSkosRelationsQuery(term.$id) + ); +}; + export type RelationResult = ReturnType extends Promise< (infer U)[] > @@ -79,3 +93,10 @@ export const useRelations = (term: TermInterface | undefined) => { notifyOnChangeProps: ["data", "isError"], }); }; + +export const useSkosRelations = (term: TermInterface | undefined) => { + return useQuery(["skos-relations", term?.$id], () => getSkosRelations(term), { + enabled: !!term, + notifyOnChangeProps: ["data", "isError"], + }); +}; diff --git a/src/api/data/terms.ts b/src/api/data/terms.ts index 76667b0..8b0033d 100644 --- a/src/api/data/terms.ts +++ b/src/api/data/terms.ts @@ -39,6 +39,11 @@ export const TermBaseSchema = { "@id": skos.definition, "@optional": true, }, + notation: { + "@id": skos.notation, + "@optional": true, + "@array": true, + }, } as const; const TermSchema = { @@ -91,10 +96,23 @@ const TermTypesSchema = { }, } as const; +const TermSkosRelationsSchema = { + "@type": skos.Concept, + related: { + "@id": skos.related, + "@array": true, + "@context": RelationItemSchema, + }, +} as const; + export type TermRelationsInterface = SchemaInterface< typeof TermRelationsSchema >; +export type TermSkosRelationsInterface = SchemaInterface< + typeof TermSkosRelationsSchema +>; + export type TermInterface = SchemaInterface; export type TermBaseInterface = SchemaInterface; @@ -107,6 +125,11 @@ export const TermsRelationsResource = createResource( context ); +export const TermsSkosRelationsResource = createResource( + TermSkosRelationsSchema, + context +); + export const getTermRelationsQuery = (termIri: string) => { const query = $` CONSTRUCT{ @@ -266,3 +289,22 @@ WHERE { return query; }; + +export const getTermSkosRelationsQuery = (termIri: string) => { + return $` + CONSTRUCT { + ?term a ${n(skos.Concept)} ; a ${n(ldkit.Resource)} . + ?term ${n(skos.related)} ?related . + ?related ${n(skos.prefLabel)} ?relatedLabel . + ?related ${n(popisDat["je-pojmem-ze-slovníku"])} ?relatedVocabulary . + ?relatedVocabulary ${n(dcterms.title)} ?relatedVocabularyTitle . + } WHERE { + BIND(${n(termIri)} as ?term) + ?term (${n(skos.related)}|${n(skos.relatedMatch)}) ?related . + ?related ${n(skos.prefLabel)} ?relatedLabel . + ?related ${n(popisDat["je-pojmem-ze-slovníku"])} ?relatedVocabulary . + ?relatedVocabulary ${n(dcterms.title)} ?relatedVocabularyTitle . + FILTER (?relatedVocabulary != ${n(HIDDEN_VOCABULARY)}) + } +`.toString(); +}; diff --git a/src/components/detail_common/DetailPageHeader.tsx b/src/components/detail_common/DetailPageHeader.tsx index e5e7f51..3805b28 100644 --- a/src/components/detail_common/DetailPageHeader.tsx +++ b/src/components/detail_common/DetailPageHeader.tsx @@ -1,10 +1,10 @@ -import React, { ReactElement } from "react"; +import React, { ReactElement, ReactNode } from "react"; import { Box, Container, Grid, Typography } from "@mui/material"; import IRI from "./IRI"; interface DetailPageHeaderProps { aboveLabel: ReactElement; - label: string; + label: ReactNode; belowLabel?: ReactElement; iri: string; } diff --git a/src/components/terms/Hierarchy.tsx b/src/components/terms/Hierarchy.tsx index b51f692..f1dec10 100644 --- a/src/components/terms/Hierarchy.tsx +++ b/src/components/terms/Hierarchy.tsx @@ -22,7 +22,7 @@ export const Hierarchy: React.FC = ({ term }) => { - Související pojmy + Hierarchie = ({ notation }) => { + return ( + <> + {notation.map((n) => ( + + ))} + + ); +}; diff --git a/src/components/terms/Relations.tsx b/src/components/terms/Relations.tsx index 88d903d..9b69641 100644 --- a/src/components/terms/Relations.tsx +++ b/src/components/terms/Relations.tsx @@ -64,7 +64,11 @@ const Relations: React.FC = ({ term }) => { ); } - return {content}; + return ( + + {content} + + ); } return null; }; diff --git a/src/components/terms/SkosRelations.tsx b/src/components/terms/SkosRelations.tsx new file mode 100644 index 0000000..1296b99 --- /dev/null +++ b/src/components/terms/SkosRelations.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import { TermInterface } from "../../api/data/terms"; +import { useSkosRelations } from "../../api/TermAPI"; +import Loader from "../Loader"; +import { isTermEmpty } from "../../utils/TermUtils"; +import EmptyTerm from "./EmptyTerm"; +import { RelationItem } from "./RelationItem"; +import { DetailItemWrapper } from "./Hierarchy"; +import { TermBox } from "./TermRelations"; + +export const SkosRelations: React.FC<{ term: TermInterface }> = ({ term }) => { + const { data, isLoading, isSuccess } = useSkosRelations(term); + + if (isLoading) { + return ; + } + if (isTermEmpty(term) && data?.length === 0) { + return ; + } + if (data?.length === 0 || data === undefined || !isSuccess) { + return null; + } + + return ( + + {data[0].related.map((item) => ( + + + + ))} + + ); +}; diff --git a/src/components/terms/TermHeader.tsx b/src/components/terms/TermHeader.tsx index 85985fd..beb9d0c 100644 --- a/src/components/terms/TermHeader.tsx +++ b/src/components/terms/TermHeader.tsx @@ -1,16 +1,18 @@ import React from "react"; +import { Box } from "@mui/material"; import AltLabel from "../detail_common/AltLabel"; import DetailPageHeader from "../detail_common/DetailPageHeader"; import RouteLink from "../RouteLink"; import { generateVocabularyRoute } from "../../utils/Utils"; import { TermInterface } from "../../api/data/terms"; +import { Notations } from "./Notations"; export interface DetailHeaderProps { term: TermInterface; } const TermHeader: React.FC = ({ term }) => { - const { $id, label, altLabels, vocabulary } = term; + const { $id, label, altLabels, notation, vocabulary } = term; const vocabularyRoute = generateVocabularyRoute(vocabulary.$id); const above = ( @@ -20,10 +22,22 @@ const TermHeader: React.FC = ({ term }) => { ); const below = ; + const title = + notation.length > 0 ? ( + <> + {label} + + + + + ) : ( + label + ); + return ( diff --git a/src/components/terms/TermPage.tsx b/src/components/terms/TermPage.tsx index f3a93ed..ba1f7ab 100644 --- a/src/components/terms/TermPage.tsx +++ b/src/components/terms/TermPage.tsx @@ -10,6 +10,7 @@ import ErrorPage from "../ErrorPage"; import Relations from "./Relations"; import useRouteQuery from "../../hooks/useRouteQuery"; import { generateTermBase } from "../../utils/Utils"; +import { SkosRelations } from "./SkosRelations"; const TermPage: React.FC = () => { const routeQuery = useRouteQuery(); @@ -36,6 +37,7 @@ const TermPage: React.FC = () => { {/**Relations component checks if the term is empty, because it is the last one**/} + ); } diff --git a/src/components/terms/TermRelations.tsx b/src/components/terms/TermRelations.tsx index 313b7c5..138e684 100644 --- a/src/components/terms/TermRelations.tsx +++ b/src/components/terms/TermRelations.tsx @@ -12,7 +12,7 @@ export interface RelationsItemProps { ranges: ReactElement[]; } -const TermBox = styled(Box)(({ theme }) => ({ +export const TermBox = styled(Box)(({ theme }) => ({ flex: 3, minWidth: 165, display: "flex",