Skip to content

Commit

Permalink
ui fixes for source id changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesamcl committed Nov 14, 2024
1 parent 18cac01 commit 16a88bf
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 30 deletions.
4 changes: 3 additions & 1 deletion webapp/grebi_api/src/main/java/uk/ac/ebi/grebi/GrebiApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ static void run(
ctx.contentType("application/json");
ctx.result("{}");

String nodeId = new String(Base64.getUrlDecoder().decode(ctx.pathParam("nodeId")));

var q = new GrebiSolrQuery();
q.addFilter("grebi:nodeId", List.of(ctx.pathParam("nodeId")), SearchType.WHOLE_FIELD, false);
q.addFilter("grebi:nodeId", List.of(nodeId), SearchType.WHOLE_FIELD, false);

var res = solr.getFirstNode(ctx.pathParam("subgraph"), q);

Expand Down
29 changes: 19 additions & 10 deletions webapp/grebi_ui/src/app/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,27 @@ export function toCamel(str: string) {


export function pickBestDisplayName(names:string[]):string|undefined {
return names.slice(0).sort((a, b) => score(b) - score(a))[0]
function score(name) {
let n = 0
for (let c of name) {
if (c.match(/[A-Za-z ]/)) {
n++
} else {
n-=10
}
return sortDisplayNamesByReadability(names)[0]
}

export function pickWorstDisplayName(names:string[]):string|undefined {
return sortDisplayNamesByReadability(names).pop()
}

export function sortDisplayNamesByReadability(names:string[]):string[] {
return names.slice(0).sort((a, b) => readabilityScore(b) - readabilityScore(a))
}

export function readabilityScore(name:string) {
let n = 0
for (let c of name) {
if (c.match(/[A-Za-z ]/)) {
n++
} else {
n-=10
}
return n
}
return n
}

export function difference(a:any[], b:any[]) {
Expand Down
33 changes: 33 additions & 0 deletions webapp/grebi_ui/src/components/CollapsingIdList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useState } from "react";
import { Fragment } from "react/jsx-runtime";

let MAX_IDS = 3

export default function CollapsingIdList({ids}) {
let [ expanded, setExpanded ] = useState<boolean>(false);
if(ids.length > MAX_IDS && !expanded) {
return <div className="my-1 leading-relaxed">
{ids.slice(0, MAX_IDS).map(id => <Id id={id}/>)}
&nbsp;
<span
className="link-default italic"
onClick={() => setExpanded(true)}
>
+ {ids.length - MAX_IDS}
</span>
</div>
} else {
return <div className="my-1 leading-relaxed">
{ids.map(id => <Id id={id}/>)}</div>
}

}

function Id({id}) {

return <span
className="bg-grey-default rounded-sm font-mono py-1 px-1 mr-1 text-sm"
>{id.value}</span>

}

Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function EdgesInList(params:{
async function getEdges() {
console.log('refreshing ', node.getNodeId(), JSON.stringify(dsEnabled), JSON.stringify(edgesState?.datasources))
setLoading(true)
let res = (await getPaginated<any>(`api/v1/subgraphs/${subgraph}/nodes/${node.getNodeId()}/incoming_edges?${
let res = (await getPaginated<any>(`api/v1/subgraphs/${subgraph}/nodes/${node.getEncodedNodeId()}/incoming_edges?${
new URLSearchParams([
['page', page],
['size', rowsPerPage],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function NodeRefLink({
}) {
let type = nodeRef.extractType()

return <Link to={`/subgraphs/${subgraph}/nodes/${encodeNodeId(nodeRef.getNodeId())}`}>
return <Link to={`/subgraphs/${subgraph}/nodes/${nodeRef.getEncodedNodeId()}`}>
{nodeRef.getName()}
{type && <NodeTypeChip type={type} />}
{/* <br/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,15 +254,15 @@ padding: '8px',
async loadShallow(node:GraphNodeRef) {

let [incomingEdgeFacets,outgoingEdgeFacets] = (await Promise.all([
getPaginated<GraphEdge>(`api/v1/subgraphs/${this.subgraph}/nodes/${node.getNodeId()}/incoming_edges?` +
getPaginated<GraphEdge>(`api/v1/subgraphs/${this.subgraph}/nodes/${node.getEncodedNodeId()}/incoming_edges?` +
new URLSearchParams([
['size', '1'],
['facet', 'grebi:type'],
['facet', 'grebi:datasources'],
...Array.from(this.dsExclude).map(ds => ['-grebi:datasources', ds])
] as any)
),
getPaginated<GraphEdge>(`api/v1/subgraphs/${this.subgraph}/nodes/${node.getNodeId()}/outgoing_edges?` +
getPaginated<GraphEdge>(`api/v1/subgraphs/${this.subgraph}/nodes/${node.getEncodedNodeId()}/outgoing_edges?` +
new URLSearchParams([
['size', '1'],
['facet', 'grebi:type'],
Expand Down
11 changes: 6 additions & 5 deletions webapp/grebi_ui/src/frontends/ebi/pages/EbiNodePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import PropTable from "../../../components/node_prop_table/PropTable";
import SearchBox from "../../../components/SearchBox";
import GraphNode from "../../../model/GraphNode";
import { get, getPaginated } from "../../../app/api";
import encodeNodeId from "../../../encodeNodeId";


export default function EbiNodePage() {
Expand All @@ -33,7 +34,7 @@ export default function EbiNodePage() {

useEffect(() => {
async function getNode() {
let graphNode = new GraphNode(await get<any>(`api/v1/subgraphs/${subgraph}/nodes/${nodeId}?lang=${lang}`))
let graphNode = new GraphNode(await get<any>(`api/v1/subgraphs/${subgraph}/nodes/${encodeNodeId(nodeId)}?lang=${lang}`))
setNode(graphNode)
}
getNode()
Expand Down Expand Up @@ -61,9 +62,9 @@ export default function EbiNodePage() {
<div className="text-center">
<Typography variant="h5">{pageTitle} {
node.extractType()?.long && <span style={{textTransform:'uppercase', fontVariant:'small-caps',fontWeight:'bold',fontSize:'small',verticalAlign:'middle',marginLeft:'12px'}}>{node.extractType()?.long}</span>}</Typography>
<Grid item xs={10} className="pt-2">
{props['id'].map(id => <span
className="bg-grey-default rounded-sm font-mono py-1 pl-2 ml-1 my-1 mb-2 text-sm"
<div>
{node.getSourceIds().map(id => <span
className="bg-grey-default rounded-sm font-mono py-1 pl-2 ml-1 my-2 text-sm"
>{id.value}
<button
onClick={() => {
Expand All @@ -74,7 +75,7 @@ className="bg-grey-default rounded-sm font-mono py-1 pl-2 ml-1 my-1 mb-2 text-sm
<i className="icon icon-common icon-copy icon-spacer" />
</button>
</span>)}
</Grid>
</div>
</div>
<Typography>{pageDesc}</Typography>
<Grid container spacing={1} direction="row">
Expand Down
7 changes: 2 additions & 5 deletions webapp/grebi_ui/src/frontends/ebi/pages/EbiSearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import LoadingOverlay from "../../../components/LoadingOverlay";
import SearchBox from "../../../components/SearchBox";
import GraphNode from "../../../model/GraphNode";
import EbiHeader from "../EbiHeader";
import CollapsingIdList from "../../../components/CollapsingIdList";

export default function EbiSearchPage() {
const [searchParams] = useSearchParams();
Expand Down Expand Up @@ -334,11 +335,7 @@ export default function EbiSearchPage() {
}
<DatasourceTags dss={graphNode.getDatasources()} />
</div>
<div className="my-1 leading-relaxed">
{graphNode.getIds().map(id => <span
className="bg-grey-default rounded-sm font-mono py-1 px-1 mr-1 text-sm"
>{id.value}</span>)}
</div>
<CollapsingIdList ids={graphNode.getSourceIds()} />
{graphNode.getDescription() && (
<div className="my-1 leading-relaxed">
{graphNode.getDescription()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ export default function EbiSearchPage() {
<DatasourceTags dss={graphNode.getDatasources()} />
</div>
<div className="my-1 leading-relaxed">
{graphNode.getIds().map(id => <span
{graphNode.getSourceIds().map(id => <span
className="bg-grey-default rounded-sm font-mono py-1 px-1 mr-1 text-sm"
>{id.value}</span>)}
</div>
Expand Down
2 changes: 1 addition & 1 deletion webapp/grebi_ui/src/model/GraphNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default class GraphNode extends GraphNodeRef {
let allIdentifiers = [
...this.getNames().map(p => p.value),
...this.getSynonyms().map(p => p.value),
...this.getIds().map(p => p.value),
...this.getSourceIds().map(p => p.value),
];
return allIdentifiers.indexOf(q) !== -1
}
Expand Down
35 changes: 32 additions & 3 deletions webapp/grebi_ui/src/model/GraphNodeRef.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

import PropVal from "./PropVal";
import { pickBestDisplayName } from "../app/util";
import { pickBestDisplayName, pickWorstDisplayName, readabilityScore } from "../app/util";
import encodeNodeId from "../encodeNodeId";

export default class GraphNodeRef {

Expand All @@ -14,6 +15,10 @@ export default class GraphNodeRef {
return this.props['grebi:nodeId']
}

getEncodedNodeId():string {
return encodeNodeId(this.props['grebi:nodeId'])
}

getDatasources():string[] {
var ds = this.props['grebi:datasources'] || []
ds.sort((a, b) => a.localeCompare(b) + (a.startsWith("OLS.") ? 10000 : 0) + (b.startsWith("OLS.") ? -10000 : 0))
Expand All @@ -39,8 +44,32 @@ export default class GraphNodeRef {
return this.props['grebi:type']
}

getIds():PropVal[] {
return PropVal.arrFrom(this.props['id'])
getSourceIds():PropVal[] {
let sids:PropVal[] = PropVal.arrFrom(this.props['grebi:sourceIds'])

// this sort order will ultimately be used in display
// ideally we will see one ID from each datasource at the beginning
// to give an idea of how many sources; and also we prefer numeric
// identifiers since this is explicitly supposed to be identifiers and
// will probably be displayed next to the readable name.

let res:PropVal[] = []

for(let ds of this.getDatasources()) {
let matches = sids.filter(sid => sid.datasources.indexOf(ds) !== -1)
if(matches.length > 0) {
res.push(matches.sort((a, b) => { return numericScore(b.value) - numericScore(a.value) })[0])
}
}

let remainder = sids.filter(sid => res.indexOf(sid) === -1)
remainder.sort((a, b) => { return numericScore(b.value) - numericScore(a.value) })

return [...res, ...remainder]

function numericScore(s:string):number {
return [...s].filter(c => c.match(/[0-9]/)).length
}
}


Expand Down

0 comments on commit 16a88bf

Please sign in to comment.