From adbb2a3fc855e6ca3ae47d457657bfd57b979a8e Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Wed, 5 Aug 2026 14:16:07 +0200 Subject: [PATCH 1/4] [GH-2] Show notations as chips next to term pref label. --- src/api/data/terms.ts | 5 +++++ .../detail_common/DetailPageHeader.tsx | 4 ++-- src/components/terms/Notations.tsx | 12 ++++++++++++ src/components/terms/TermHeader.tsx | 18 ++++++++++++++++-- 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/components/terms/Notations.tsx diff --git a/src/api/data/terms.ts b/src/api/data/terms.ts index 76667b0..d94f5a8 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 = { 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/Notations.tsx b/src/components/terms/Notations.tsx new file mode 100644 index 0000000..71acd24 --- /dev/null +++ b/src/components/terms/Notations.tsx @@ -0,0 +1,12 @@ +import React from "react"; +import { Chip } from "@mui/material"; + +export const Notations: React.FC<{ notation: string[] }> = ({ notation }) => { + return ( + <> + {notation.map((n) => ( + + ))} + + ); +}; 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 ( From 329cd51b4420aec2d8610bbab4dde50d5031d485 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Wed, 5 Aug 2026 15:12:40 +0200 Subject: [PATCH 2/4] [GH-2] Show skos:related(Match) terms for a term. --- src/api/TermAPI.ts | 21 +++++++++++++++ src/api/data/terms.ts | 37 ++++++++++++++++++++++++++ src/components/terms/Hierarchy.tsx | 2 +- src/components/terms/Relations.tsx | 6 ++++- src/components/terms/SkosRelations.tsx | 37 ++++++++++++++++++++++++++ src/components/terms/TermPage.tsx | 2 ++ src/components/terms/TermRelations.tsx | 2 +- 7 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 src/components/terms/SkosRelations.tsx 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 d94f5a8..8b0033d 100644 --- a/src/api/data/terms.ts +++ b/src/api/data/terms.ts @@ -96,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; @@ -112,6 +125,11 @@ export const TermsRelationsResource = createResource( context ); +export const TermsSkosRelationsResource = createResource( + TermSkosRelationsSchema, + context +); + export const getTermRelationsQuery = (termIri: string) => { const query = $` CONSTRUCT{ @@ -271,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/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 = ({ 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/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", From 7f9300a15b684e97847970fa5cc8f2f99e6d0c3a Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Wed, 5 Aug 2026 15:18:22 +0200 Subject: [PATCH 3/4] Add GH build workflow for PR and pushes to main. --- .github/workflows/build.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..f684626 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,26 @@ +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@v6 + - name: Use Node.js + uses: actions/setup-node@v6 + with: + node-version: "18.x" + - name: Install + run: npm ci --ignore-scripts + - name: Prettier Check + run: npm run prettier:check + - name: Build + run: npm run-script build + env: + CI: "" From 297b6c44c295cf7a78e526a8e63dee5ab05ccecc Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Wed, 5 Aug 2026 15:23:12 +0200 Subject: [PATCH 4/4] Update actions, use cache in GH action --- .github/workflows/build.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f684626..a9bb80a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,11 +11,12 @@ jobs: runs-on: ubuntu-latest steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Use Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: - node-version: "18.x" + node-version: "24.x" + cache: "npm" - name: Install run: npm ci --ignore-scripts - name: Prettier Check