Skip to content

Commit

Permalink
wxposomekg tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesamcl committed Dec 6, 2024
1 parent 002679f commit 497cd13
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 92 deletions.
4 changes: 4 additions & 0 deletions webapp/grebi_ui/src/app/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ export async function request(
apiUrl?: string
): Promise<any> {
const url = (apiUrl || process.env.REACT_APP_APIURL) + path;
const message = `Loading ${url}`
console.log(message)
console.time(message)
//const res = await fetch(url.replace(/([^:]\/)\/+/g, "$1"), {
const res = await fetch(url + (reqParams ? ('?' + buildSearchParams(reqParams)) : ''), {
...(init ? init : {}),
//headers: { ...(init?.headers || {}), ...getAuthHeaders() }
});
console.timeEnd(message)
if (!res.ok) {
const message = `Failure loading ${res.url} with status ${res.status} (${res.statusText})`;
console.dir(message);
Expand Down
28 changes: 28 additions & 0 deletions webapp/grebi_ui/src/components/TabPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Box, Typography } from "@mui/material";

export interface TabPanelProps {
children?: React.ReactNode;
index: string;
value: string;
}

export default function TabPanel(props: TabPanelProps) {
const { children, value, index, ...other } = props;

return (
<div
role="tabpanel"
hidden={value !== index}
id={`vertical-tabpanel-${index}`}
aria-labelledby={`vertical-tab-${index}`}
{...other}
>
{value === index && (
// <Box sx={{ p: 3 }}>
<Typography>{children}</Typography>
// </Box>
)}
</div>
);
}

6 changes: 5 additions & 1 deletion webapp/grebi_ui/src/components/datatable/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export default function DataTable({
sortColumn,
setSortColumn,
sortDir,
setSortDir
setSortDir,
maxRowHeight
}: {
columns?: readonly Column[]|undefined;
defaultSelector:undefined|((row:any, key:string)=>any);
Expand All @@ -49,6 +50,7 @@ export default function DataTable({
setSortColumn?: (sortColumn: string) => void,
sortDir?: 'asc'|'desc',
setSortDir?: (sortDir: 'asc'|'desc') => void,
maxRowHeight?:string|undefined
}) {

let [autoAddedColumns, setAutoAddedColumns] = useState<Column[]>([])
Expand Down Expand Up @@ -186,9 +188,11 @@ export default function DataTable({
className="text-md align-top py-2 px-4"
key={randomString()}
>
<div style={{ ...( maxRowHeight ? {maxHeight: maxRowHeight, overflowY:"scroll"} : {}) }}>
{column.selector(row, column.id)
? column.selector(row, column.id)
: "(no data)"}
</div>
</td>
);
})}
Expand Down
28 changes: 21 additions & 7 deletions webapp/grebi_ui/src/components/datatable/LocalDataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,49 @@ export default function LocalDataTable({
hideColumns,
addColumnsFromData,
defaultSelector,
onSelectRow
onSelectRow,
maxRowHeight
}:{
data: any[],
columns?: readonly Column[]|undefined,
hideColumns?: string[]|undefined,
addColumnsFromData?:boolean,
defaultSelector:undefined|((row:any, key:string)=>any);
onSelectRow?: (row: any) => void
onSelectRow?: (row: any) => void,
maxRowHeight?:string|undefined
}) {

let [page, setPage] = useState(0)
let [page, setPage] = useState(1)
let [rowsPerPage, setRowsPerPage] = useState(10)
let [sortColumn, setSortColumn] = useState<string|undefined>("")
let [sortDir, setSortDir] = useState<'asc'|'desc'>("asc")
let [filter, setFilter] = useState<string>("")

let filteredData = data.filter(row => {
data = data.filter(row => {
return Object.values(row).some(v => {
return (v+'').toLowerCase().includes(filter.toLowerCase())
})
});

data = data.slice((page-1)*rowsPerPage, page*rowsPerPage)

return <DataTable
data={filteredData}
data={data}
columns={columns}
addColumnsFromData={addColumnsFromData}
hideColumns={hideColumns}
dataCount={filteredData.length}
dataCount={data.length}
defaultSelector={defaultSelector}
onFilter={setFilter}
rowsPerPage={rowsPerPage}
onRowsPerPageChange={setRowsPerPage}
page={page}
onPageChange={setPage}
sortColumn={sortColumn}
setSortColumn={setSortColumn}
sortDir={sortDir}
setSortDir={setSortDir}
onSelectRow={onSelectRow}
maxRowHeight={maxRowHeight}
/>

}
24 changes: 0 additions & 24 deletions webapp/grebi_ui/src/components/datatable/renderValueBestEffort.tsx

This file was deleted.

75 changes: 47 additions & 28 deletions webapp/grebi_ui/src/components/exposomekg/ExposureLinks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Fragment, useEffect, useState } from "react";
import GraphNode from "../../model/GraphNode";
import { getPaginated, Page } from "../../app/api";
import encodeNodeId from "../../encodeNodeId";
import { CircularProgress, Grid, Typography } from "@mui/material";
import { CircularProgress, Grid, Tab, Tabs, Typography } from "@mui/material";
import { asArray, copyToClipboard } from "../../app/util";
import LocalDataTable from "../datatable/LocalDataTable";
import NodeRefLink from "../node_edge_list/NodeRefLink";
Expand All @@ -12,37 +12,53 @@ import { DatasourceTags } from "../DatasourceTag";
import Refs from "../../model/Refs";
import PropVals from "../node_prop_table/PropVals";
import PropVal from "../../model/PropVal";
import { useSearchParams } from "react-router-dom";
import getExposureLinksTabs, { LinksTab } from "./getExposureLinksTabs";
import { OpenInNew, Share } from "@mui/icons-material";
import TabPanel from "../TabPanel";


export default function ExposureLinks({node}:{node:GraphNode}) {

let type = node.extractType()
var links:any = null
if(type) {
if(type.short === 'Gene') {
links = <GeneExposureLinks node={node} />
}
if(type.short === 'Chemical') {
links = <ChemicalExposureLinks node={node} />
}
}
let [searchParams, setSearchParams] = useSearchParams();
let linksTab = searchParams.get("linksTab") || "sourceids";

let [linksTabs, setLinksTabs] = useState<LinksTab[]>([])

return <div>
<ExpandableSection title="Source IDs">
useEffect(() => {
async function getLinksTabs() {
let tabs = await getExposureLinksTabs(node)
setLinksTabs(tabs)
}
getLinksTabs()
}, [node])

return <Grid container spacing={1} direction="column" className="py-0">
<Grid item xs={2} className="py-0">
<Tabs orientation="horizontal" value={linksTab} className="bg-gray-100 border-black justify-center rounded-lg" sx={{ borderBottom: 1, borderColor: 'divider' }} onChange={(e, tab) => setSearchParams({linksTab:tab})}>
<Tab label={
<div><OpenInNew fontSize="small" style = { {verticalAlign : 'middle'} } /> Source IDs </div>
} value={"sourceids"} className="grebi-subtab" />
{linksTabs.map(tab => <Tab label={
<div><OpenInNew fontSize="small" style = { {verticalAlign : 'middle'} } /> {tab.tabName} </div>
} value={tab.tabId} className="text-black" />)}
</Tabs>
</Grid>
<Grid item xs={10}>
<TabPanel value={linksTab} index={"sourceids"}>
<Grid container spacing={0.5} direction="row" alignItems={"left"} justifyContent={"left"} className="pb-5">
{node.getSourceIds().map(id => <Grid item>
<div className="bg-grey-default rounded-sm font-mono pl-1" style={{fontSize:'small'}}>
{id.value} <button onClick={() => { copyToClipboard(id.value); }} >
<i className="icon icon-common icon-copy icon-spacer" />
</button>
</div>
</Grid>
)}
</Grid>
</ExpandableSection>
{links && links}
</div>
{node.getSourceIds().map(id => <Grid item>
<div className="bg-grey-default rounded-sm font-mono pl-1" style={{fontSize:'small'}}>
{id.value} <button onClick={() => { copyToClipboard(id.value); }} >
<i className="icon icon-common icon-copy icon-spacer" />
</button>
</div>
</Grid>
)}
</Grid>
</TabPanel>
</Grid>
</Grid>
}


Expand All @@ -51,11 +67,13 @@ let fixedCols = [
id: "grebi:datasources",
name: "Datasources",
selector: (edge:GraphEdge, key:string) => <DatasourceTags dss={edge['grebi:datasources']} />,
sortable:true
},
{
id: "from",
name: "Chemical",
selector: (edge:GraphEdge, key:string) => <NodeRefLink subgraph={process.env.REACT_APP_EXPOSOMEKG_SUBGRAPH!} nodeRef={new GraphNodeRef(edge['from'])} showTypeChip={false} />,
sortable:true
}
];

Expand Down Expand Up @@ -91,16 +109,17 @@ function GeneExposureLinks({node}:{node:GraphNode}) {
return <div>
<ExpandableSection title={
affectedBy ?
`Gene-chemical interactions (${affectedBy.totalElements})`
`Chemical interactions (${affectedBy.totalElements})`
:
`Gene-chemical interactions (Loading...)`
<Fragment>Chemical interactions <i color="gray">(Loading...)</i></Fragment>
} loading={!affectedBy}>

{affectedBy &&
<LocalDataTable
data={affectedBy?.elements}
addColumnsFromData={true}
columns={fixedCols}
maxRowHeight={"1.5em"}
defaultSelector={DefaultSelector}
hideColumns={[
"_refs",
Expand Down Expand Up @@ -130,7 +149,7 @@ function ChemicalExposureLinks({node}:{node:GraphNode}) {



function ExpandableSection({title, loading, children}) {
function ExpandableSection({title, loading, children}:{title:string, loading?:boolean|undefined, children:any}) {

let [expanded, setExpanded] = useState<boolean>(false);

Expand Down
35 changes: 35 additions & 0 deletions webapp/grebi_ui/src/components/exposomekg/getExposureLinksTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { getPaginated } from "../../app/api";
import encodeNodeId from "../../encodeNodeId";
import GraphNode from "../../model/GraphNode";

export interface LinksTab {
tabId:string,
tabName:string,
count:number
}

export default async function getExposureLinksTabs(node:GraphNode):Promise<LinksTab[]> {

let type = node.extractType()
let metadata_promises:any = []

if(type?.short === 'Gene') {
metadata_promises.push(getGeneLinksTabs(node))
}

return await Promise.all(metadata_promises)
}

async function getGeneLinksTabs(node:GraphNode) {

let page = await (getPaginated<any>(`api/v1/subgraphs/${node.getSubgraph()}/nodes/${encodeNodeId(node.getNodeId())}/incoming_edges`, {
'size': "0",
'grebi:type': 'biolink:chemical_gene_interaction_association'
}));

return {
tabId: "chemical_gene_interactions",
tabName: "Chemical Interactions",
count: page.totalElements
}
}
6 changes: 5 additions & 1 deletion webapp/grebi_ui/src/css/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -1403,4 +1403,8 @@ filter: gray;
.button-primary {
background-color: var(--grebi-base-color);
border-color: var(--grebi-base-color);
}
}
.grebi-subtab {
color: black !important;
text-transform: none !important;
}
35 changes: 4 additions & 31 deletions webapp/grebi_ui/src/frontends/exposomekg/pages/EkgNodePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import GraphNode from "../../../model/GraphNode";
import { get, getPaginated } from "../../../app/api";
import encodeNodeId from "../../../encodeNodeId";
import ExposureLinks from "../../../components/exposomekg/ExposureLinks";
import TabPanel from "../../../components/TabPanel";


export default function EkgNodePage() {
Expand Down Expand Up @@ -79,15 +80,15 @@ export default function EkgNodePage() {
<ExposureLinks node={node} />
</TabPanel>
<TabPanel value={tab} index={"properties"}>
<PropTable lang={lang} subgraph={process.env.REACT_APP_EXPOSOMEKG_SUBGRAPH} node={node} />
<PropTable lang={lang} subgraph={process.env.REACT_APP_EXPOSOMEKG_SUBGRAPH!} node={node} />
</TabPanel>
<TabPanel value={tab} index={"edges_in"}>
<EdgesInList subgraph={process.env.REACT_APP_EXPOSOMEKG_SUBGRAPH} node={node} />
<EdgesInList subgraph={process.env.REACT_APP_EXPOSOMEKG_SUBGRAPH!} node={node} />
</TabPanel>
<TabPanel value={tab} index={"edges_out"}>
</TabPanel>
<TabPanel value={tab} index={"graph"}>
<GraphView subgraph={process.env.REACT_APP_EXPOSOMEKG_SUBGRAPH} node={node} />
<GraphView subgraph={process.env.REACT_APP_EXPOSOMEKG_SUBGRAPH!} node={node} />
</TabPanel>
</Grid>
</Grid>
Expand All @@ -96,31 +97,3 @@ export default function EkgNodePage() {
</div>
);
}

interface TabPanelProps {
children?: React.ReactNode;
index: string;
value: string;
}

function TabPanel(props: TabPanelProps) {
const { children, value, index, ...other } = props;

return (
<div
role="tabpanel"
hidden={value !== index}
id={`vertical-tabpanel-${index}`}
aria-labelledby={`vertical-tab-${index}`}
{...other}
>
{value === index && (
<Box sx={{ p: 3 }}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}


0 comments on commit 497cd13

Please sign in to comment.