From 3b4b7de8398340bad311d79bee0228e146f1ff25 Mon Sep 17 00:00:00 2001 From: Dario Del Piano Date: Thu, 30 Jul 2026 10:54:19 +0200 Subject: [PATCH] fixing active ontology for new ones created --- .../Dashboard/Ontologies/OntologyCard.jsx | 67 +++++++++ src/components/Dashboard/Ontologies/index.jsx | 135 ++++++++++++++++++ src/components/Dashboard/index.jsx | 2 + .../AddNewOntologyDialog.jsx | 35 ++++- src/components/SingleTermView/index.jsx | 6 +- 5 files changed, 241 insertions(+), 4 deletions(-) create mode 100644 src/components/Dashboard/Ontologies/OntologyCard.jsx create mode 100644 src/components/Dashboard/Ontologies/index.jsx diff --git a/src/components/Dashboard/Ontologies/OntologyCard.jsx b/src/components/Dashboard/Ontologies/OntologyCard.jsx new file mode 100644 index 00000000..babe13b9 --- /dev/null +++ b/src/components/Dashboard/Ontologies/OntologyCard.jsx @@ -0,0 +1,67 @@ +import PropTypes from 'prop-types'; +import {Box, Chip, Grid, Stack, Typography} from "@mui/material"; + +import { vars } from "../../../theme/variables"; +const {gray500, gray700, gray200, brand600, brand200, brand50 } = vars; + +const OntologyCard = ({ ontology, onSelect }) => { + const handleClick = () => { + // The cell card overview component is not built yet - the parent shows a + // placeholder dialog for now. + onSelect(ontology); + }; + + return ( + + + + + {ontology?.label} + {ontology?.badge && } + + + + {ontology?.description ? ontology?.description : '-'} + + + + ); +}; + +OntologyCard.propTypes = { + ontology: PropTypes.object.isRequired, + onSelect: PropTypes.func.isRequired +}; + +export default OntologyCard; diff --git a/src/components/Dashboard/Ontologies/index.jsx b/src/components/Dashboard/Ontologies/index.jsx new file mode 100644 index 00000000..c8231db5 --- /dev/null +++ b/src/components/Dashboard/Ontologies/index.jsx @@ -0,0 +1,135 @@ +import OntologyCard from "./OntologyCard"; +import { useCallback, useContext, useEffect, useState } from "react"; +import { ListIcon, TableChartIcon } from "../../../Icons"; +import CustomPagination from "../../common/CustomPagination"; +import CustomViewButton from "../../common/CustomViewButton"; +import CustomSingleSelect from "../../common/CustomSingleSelect"; +import MessageDialog from "../../common/MessageDialog"; +import { getOrganizationsOntologies } from "../../../api/endpoints/apiService"; +import {Box, ButtonGroup, CircularProgress, Grid, Stack, Typography} from "@mui/material"; +import { GlobalDataContext } from "../../../contexts/DataContext"; + +import { vars } from "../../../theme/variables"; +const { gray600 } = vars; + +const NOT_IMPLEMENTED_MESSAGE = "The cell card overview is not yet implemented"; + +const Ontologies = () => { + const { user } = useContext(GlobalDataContext); + const groupname = user?.groupname; + const [loading, setLoading] = useState(false); + const [numberOfVisiblePages, setNumberOfVisiblePages] = useState(8); + const [listView, setListView] = useState('list'); + const [ontologies, setOntologies] = useState([]); + const [page, setPage] = useState(1); + const [slicedOntologies, setSlicedOntologies] = useState([]); + const [message, setMessage] = useState(''); + + const handleNumberOfPagesChange = (v) => { + setNumberOfVisiblePages(v); + setPage(1); + }; + + const fetchOntologies = useCallback(async () => { + if (!groupname) return; + setLoading(true); + getOrganizationsOntologies(groupname).then(data => { + // Same transform as OntologySearch: derive a readable label, fall back to + // an identifier parsed from the spec URI when there's no title. + const parsed = (Array.isArray(data) ? data : []).map((ontology, index) => { + let fallbackLabel = `Unknown Ontology ${ontology.id || index + 1}`; + if (ontology.uri) { + const uriParts = ontology.uri.split('/'); + const specIndex = uriParts.findIndex(part => part === 'spec'); + if (specIndex > 0) { + fallbackLabel = `Ontology ${uriParts[specIndex - 1]}`; + } + } + return { + label: ontology.title || fallbackLabel, + badge: groupname, + id: ontology.id || `ontology-${index}`, + description: ontology.uri, + url: ontology.url, + }; + }); + setOntologies(parsed); + setPage(1); + setLoading(false); + }).catch(err => { + console.log(err); + setLoading(false); + }); + }, [groupname]); + + useEffect(() => { + fetchOntologies(); + }, [fetchOntologies]); + + useEffect(() => { + const start = (page - 1) * numberOfVisiblePages; + const end = start + numberOfVisiblePages; + setSlicedOntologies(ontologies.slice(start, end)); + }, [ontologies, page, numberOfVisiblePages]); + + const handlePageChange = (event, value) => { + setPage(value); + }; + + const handleSelectOntology = () => { + // Placeholder until the cell card overview component is developed. + setMessage(NOT_IMPLEMENTED_MESSAGE); + }; + + return ( + + + + My ontologies + + + + Show on page: + + + + setListView('list')} + icon={} + /> + setListView('table')} + icon={} + /> + + + + {loading ? + + : + { + slicedOntologies.map((ontology, index) => ( + + )) + } + } + + {message && setMessage('')} message={message} />} + + ); +}; + +export default Ontologies; diff --git a/src/components/Dashboard/index.jsx b/src/components/Dashboard/index.jsx index 15de8a4f..2f4838b5 100644 --- a/src/components/Dashboard/index.jsx +++ b/src/components/Dashboard/index.jsx @@ -2,6 +2,7 @@ import {Box} from "@mui/material"; import { useState } from "react"; import EditBulkTermsDialog from "./EditBulkTerms/EditBulkTermsDialog"; import Variants from "./Variants"; +import Ontologies from "./Ontologies"; import TermsChange from "./TermsChange"; import Organizations from "./Organizations"; import User from "./User"; @@ -22,6 +23,7 @@ const Dashboard = () => { + diff --git a/src/components/SingleOrganization/AddNewOntologyDialog.jsx b/src/components/SingleOrganization/AddNewOntologyDialog.jsx index afe39edf..5a38be30 100644 --- a/src/components/SingleOrganization/AddNewOntologyDialog.jsx +++ b/src/components/SingleOrganization/AddNewOntologyDialog.jsx @@ -8,7 +8,7 @@ import CustomizedDialog from "../common/CustomizedDialog"; import ImportFileTab from "./../TermEditor/ImportFileTab"; import BasicTabs from "../common/CustomTabs"; import { useState, useCallback } from "react"; -import { createNewOntology } from "../../api/endpoints/apiService"; +import { createNewOntology, getOntologyTerms } from "../../api/endpoints/apiService"; import { API_CONFIG } from "../../config"; import { GlobalDataContext } from "../../contexts/DataContext"; import { useContext } from "react"; @@ -49,7 +49,8 @@ const AddNewOntologyDialog = ({ open, handleClose, onOntologyAdded, organization const [files, setFiles] = useState([]); const [url, setUrl] = useState(''); const [tabValue, setTabValue] = useState(0); - const { user, refreshOntologies } = useContext(GlobalDataContext); + const [setAsActive, setSetAsActive] = useState(false); + const { user, refreshOntologies, setOntologyData } = useContext(GlobalDataContext); // group used both for the POST endpoint and the immutable URI prefix shown to the user const groupForUri = organizationName || user?.groupname || "base"; @@ -64,6 +65,7 @@ const AddNewOntologyDialog = ({ open, handleClose, onOntologyAdded, organization setFiles([]); setUrl(''); setTabValue(0); + setSetAsActive(false); setOpenStatusDialog(false); setNewOntologyResponse({ title: "", @@ -118,6 +120,28 @@ const AddNewOntologyDialog = ({ open, handleClose, onOntologyAdded, organization // If ontology was created successfully, trigger refresh if (result.created) { refreshOntologies(); + + // Honor the "Set as active ontology" checkbox: push the freshly + // created ontology into global context so the active-ontology + // selector reflects it. The object shape mirrors the transformed + // ontologies produced in OntologySearch (label/badge/id/description/url). + if (setAsActive) { + const ontologyUri = `${API_CONFIG.INTERLEX_URL}/${groupname}/ontologies/uris/${ontologyName}/spec`; + const activeOntology = { + label: title, + badge: groupname, + selected: true, + id: result.newOntologyID || ontologyUri, + description: ontologyUri, + url: result.location, + }; + setOntologyData(activeOntology); + // Enrich with member terms once fetched, same as OntologySearch.onSetActive. + getOntologyTerms(ontologyUri) + .then((terms) => setOntologyData({ ...activeOntology, terms })) + .catch(() => setOntologyData({ ...activeOntology, terms: [] })); + } + if (onOntologyAdded) { onOntologyAdded(); } @@ -382,7 +406,12 @@ const AddNewOntologyDialog = ({ open, handleClose, onOntologyAdded, organization }} /> - + setSetAsActive(e.target.checked)} + /> { {versionHash && ( - + navigate(`/${group}/${term}/overview`)} + closeText="Back to current term" + > Viewing a historical version of this term (identity graph {versionHash}). This snapshot is read-only.