From cfb829b8be8f587d72955c8d44a75a5362898d58 Mon Sep 17 00:00:00 2001 From: Carlos Cruz Date: Tue, 24 Sep 2024 13:39:53 +0100 Subject: [PATCH] [Platform]: AotF Target interactors UI recap (#489) --- .../RowInteractors/RowInteractorsTable.tsx | 72 +++-------- .../RowInteractors/useRowInteractors.js | 26 +++- .../components/Table/CellName.jsx | 22 +++- .../components/Table/SectionRender.jsx | 82 ++++++------- .../components/Table/TableBody.jsx | 116 ++++++++++-------- .../AssociationsToolkit/components/layout.tsx | 1 + .../context/AssociationsFocusContext.tsx | 7 +- 7 files changed, 176 insertions(+), 150 deletions(-) diff --git a/apps/platform/src/components/AssociationsToolkit/components/RowInteractors/RowInteractorsTable.tsx b/apps/platform/src/components/AssociationsToolkit/components/RowInteractors/RowInteractorsTable.tsx index 5e326e8eb..5e28f3bc3 100644 --- a/apps/platform/src/components/AssociationsToolkit/components/RowInteractors/RowInteractorsTable.tsx +++ b/apps/platform/src/components/AssociationsToolkit/components/RowInteractors/RowInteractorsTable.tsx @@ -40,8 +40,7 @@ type ThresholdState = number | null | undefined; const INTERACTORS_SOURCE_LABEL = ( assoc: number, interactors: number, - source: InteractorsSource, - targetName: string + source: InteractorsSource ): ReactElement => { const interactorTypeMap = { [INTERACTORS_SOURCES.REACTOME]: "pathway-based", @@ -55,8 +54,7 @@ const INTERACTORS_SOURCE_LABEL = ( return ( <> {assoc} target-disease association{assoc === 1 ? "" : "s"} found for{" "} - {interactors} {interactorType} interactor{interactors === 1 ? "" : "s"} of{" "} - {targetName} + {interactors} {interactorType} interactor{interactors === 1 ? "" : "s"} ); }; @@ -73,18 +71,15 @@ const btnStyles = { const leftBTNStyles = { ...btnStyles, - background: grey[300], - marginRight: 2, + marginRight: 1, }; const rightBTNStyles = { ...btnStyles, - marginLeft: 2, - borderLeft: "1px solid", + marginRight: 2, borderColor: grey[400], cursor: "pointer", "&:hover": { - background: grey[300], color: "#000", }, }; @@ -107,24 +102,6 @@ const OTSlider = styled(Slider)({ }, }); -function RowLine() { - return ( - - ); -} - function RowInteractorsTable({ row, columns, nameProperty, parentTable }) { const { id: diseaseId, @@ -221,14 +198,11 @@ function RowInteractorsTable({ row, columns, nameProperty, parentTable }) { return ( - - + - Interactors + Interactors for {label} - - {loading ? ( - - ) : ( - - {INTERACTORS_SOURCE_LABEL( - data?.length, - interactorsMetadata?.count, - focusElement?.interactorsSource, - label - )} - - )} + @@ -335,11 +291,23 @@ function RowInteractorsTable({ row, columns, nameProperty, parentTable }) { )} + {loading ? ( + + ) : ( + + {INTERACTORS_SOURCE_LABEL( + data?.length, + interactorsMetadata?.count, + focusElement?.interactorsSource, + label + )} + + )} onClickCloseInteractors()} sx={rightBTNStyles}> - + diff --git a/apps/platform/src/components/AssociationsToolkit/components/RowInteractors/useRowInteractors.js b/apps/platform/src/components/AssociationsToolkit/components/RowInteractors/useRowInteractors.js index 7e824025d..9dfbf2ffd 100644 --- a/apps/platform/src/components/AssociationsToolkit/components/RowInteractors/useRowInteractors.js +++ b/apps/platform/src/components/AssociationsToolkit/components/RowInteractors/useRowInteractors.js @@ -66,7 +66,14 @@ function useRowInteractors({ }, }); - if (!targetRowInteractorsRequest.data) { + if (!targetRowInteractorsRequest?.data?.target?.interactions?.rows) { + setState({ + interactorsMetadata: { count: 0 }, + loading: false, + initialLoading: false, + count: 0, + data: [], + }); return; } @@ -96,12 +103,17 @@ function useRowInteractors({ interactorsAssociationsRequest.data ); + const interactorsAssociationsWithScore = addInteractorScore( + interactorsAssociations, + targetRowInteractorsRequest.data.target.interactions.rows + ); + setState({ interactorsMetadata: targetRowInteractorsRequest.data.target.interactions, loading: false, initialLoading: false, - count: interactorsAssociations.length, - data: interactorsAssociations, + count: interactorsAssociationsWithScore.length, + data: interactorsAssociationsWithScore, }); } if (isCurrent) getInteractors(); @@ -111,4 +123,12 @@ function useRowInteractors({ return state; } +function addInteractorScore(associationsData, interactorsMetaData) { + return associationsData.map(element => { + const foundInteractor = interactorsMetaData.find(x => x.targetB?.id === element.id); + if (!foundInteractor) return { ...element, interactorScore: 0 }; + return { ...element, interactorScore: foundInteractor.score }; + }); +} + export default useRowInteractors; diff --git a/apps/platform/src/components/AssociationsToolkit/components/Table/CellName.jsx b/apps/platform/src/components/AssociationsToolkit/components/Table/CellName.jsx index ee1579e59..4b93fe916 100644 --- a/apps/platform/src/components/AssociationsToolkit/components/Table/CellName.jsx +++ b/apps/platform/src/components/AssociationsToolkit/components/Table/CellName.jsx @@ -117,6 +117,11 @@ function CellName({ cell, colorScale }) { }); }; + const handleContextMenu = e => { + e.preventDefault(); + handleToggle(); + }; + const handleToggle = () => { setOpenContext(true); dispatch({ @@ -196,15 +201,30 @@ function CellName({ cell, colorScale }) { return ( - + {name} + {prefix === TABLE_PREFIX.INTERACTORS && cell.row.original.interactorScore ? ( + <> + {" "} + - + + {cell.row.original.interactorScore.toFixed(2)} + + + ) : ( + "" + )} diff --git a/apps/platform/src/components/AssociationsToolkit/components/Table/SectionRender.jsx b/apps/platform/src/components/AssociationsToolkit/components/Table/SectionRender.jsx index 96fdc5ea7..72303ef55 100644 --- a/apps/platform/src/components/AssociationsToolkit/components/Table/SectionRender.jsx +++ b/apps/platform/src/components/AssociationsToolkit/components/Table/SectionRender.jsx @@ -20,9 +20,10 @@ const LoadingContainer = styled("div")({ const Container = styled("div", { shouldForwardProp: prop => prop !== "table", })(({ table, theme }) => ({ - paddingTop: "10px", - paddingBottom: "10px", - paddingLeft: table === "interactors" ? theme.spacing(9) : theme.spacing(3), + paddingTop: theme.spacing(2), + paddingBottom: theme.spacing(2), + paddingLeft: table === "interactors" ? theme.spacing(6) : theme.spacing(3), + paddingRight: table === "interactors" ? theme.spacing(6) : theme.spacing(3), background: grey[100], })); @@ -39,10 +40,36 @@ function SectionNotFound() { return
Section not found
; } +const getComponentConfig = (displayedTable, row, entity, id, section) => { + switch (displayedTable) { + case "prioritisations": + return { + Component: targetSections.get(section[1]), + componentId: entity === ENTITIES.DISEASE ? row.id : id, + label: row.original.targetSymbol, + entityOfSection: "target", + }; + case "associations": + return { + Component: evidenceSections.get(section[1]), + componentId: { + ensgId: entity === ENTITIES.DISEASE ? row.id : id, + efoId: entity === ENTITIES.DISEASE ? id : row.id, + }, + label: { + symbol: row.original.targetSymbol, + name: row.original.diseaseName, + }, + entityOfSection: "disease", + }; + default: + return { Component: SectionNotFound }; + } +}; + export function SectionRender({ id, entity, - focusElement, row, table, entityToGet, @@ -51,44 +78,17 @@ export function SectionRender({ cols = [], section, }) { - let label = row.original[entityToGet][nameProperty]; - let ensgId; - let efoId; - let componentId; - let Component; - let entityOfSection = entity; - - if (section === undefined) return <>; - - // const section = focusElement - - const flatCols = cols.map(c => c.id); - if (!flatCols.includes(section[0])) return <>; - - switch (displayedTable) { - case "prioritisations": { - Component = targetSections.get(section[1]); - const { targetSymbol } = row.original; - ensgId = entity === ENTITIES.DISEASE ? row.id : id; - label = targetSymbol; - componentId = ensgId; - entityOfSection = "target"; - break; - } - case "associations": { - Component = evidenceSections.get(section[1]); - const { diseaseName, targetSymbol } = row.original; - ensgId = entity === ENTITIES.DISEASE ? row.id : id; - efoId = entity === ENTITIES.DISEASE ? id : row.id; - componentId = { ensgId, efoId }; - label = { symbol: targetSymbol, name: diseaseName }; - entityOfSection = "disease"; - break; - } - default: - return ; + if (!section || !cols.some(c => c.id === section[0])) { + return null; } + const { + Component, + componentId, + label = row.original[entityToGet][nameProperty], + entityOfSection = entity, + } = getComponentConfig(displayedTable, row, entity, id, section); + if (!Component) return ; return ( @@ -99,6 +99,6 @@ export function SectionRender({ } export function SectionRendererWrapper({ children, section }) { - if (!section) return <>; + if (!section) return null; return }>{children}; } diff --git a/apps/platform/src/components/AssociationsToolkit/components/Table/TableBody.jsx b/apps/platform/src/components/AssociationsToolkit/components/Table/TableBody.jsx index a6a559c6a..dba559517 100644 --- a/apps/platform/src/components/AssociationsToolkit/components/Table/TableBody.jsx +++ b/apps/platform/src/components/AssociationsToolkit/components/Table/TableBody.jsx @@ -1,6 +1,6 @@ import { Fragment } from "react"; import { flexRender } from "@tanstack/react-table"; -import { ClickAwayListener, Fade, Box, Typography } from "@mui/material"; +import { Fade, Box, Typography } from "@mui/material"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faFilterCircleXmark } from "@fortawesome/free-solid-svg-icons"; import { grey } from "@mui/material/colors"; @@ -20,6 +20,41 @@ const getColContainerClassName = ({ id }) => { return "group-entity-cols"; }; +function getIsRowActive(prefix, row, focusState = [], parentRow, parentTable) { + if (prefix === TABLE_PREFIX.INTERACTORS) { + return focusState.some( + entry => + entry.row === parentRow && + entry.table === parentTable && + entry.interactorsRow === row.id && + entry.interactorsSection !== null + ); + } + + return focusState.some( + entry => + entry.row === row.id && + entry.table === prefix && + (entry.section !== null || entry.interactors) + ); +} + +function getFocusSection(prefix, row, focusState, parentRow, parentTable) { + if (prefix === TABLE_PREFIX.INTERACTORS) { + return focusState.find( + entry => + entry.row === parentRow && + entry.table === parentTable && + entry.interactorsRow === row.id && + entry.interactorsSection !== null + )?.interactorsSection; + } + + return focusState.find( + entry => entry.row === row.id && entry.table === prefix && entry.section !== null + )?.section; +} + function EmptyMessage() { return ( { - if (e.srcElement.className === "CodeMirror-hint CodeMirror-hint-active") { - return; - } - // resetExpandler(); - }; - return ( @@ -110,51 +140,35 @@ function TableBody({ core, cols, noInteractors }) { ))} - + e.row === row.id && e.table === prefix && e.section !== null - )?.section - : focusState.find( - e => - e.row === parentRow && - e.table === parentTable && - e.interactorsRow === row.id && - e.interactorsSection !== null - )?.interactorsSection - } + section={getFocusSection(prefix, row, focusState, parentRow, parentTable)} > - handleClickAway(e)}> -
- e.row === row.id && e.table === prefix && e.section !== null - )?.section - : focusState.find( - e => - e.row === parentRow && - e.table === parentTable && - e.interactorsRow === row.id && - e.interactorsSection !== null - )?.interactorsSection - } - /> -
-
+
+ +
{!noInteractors && ( diff --git a/apps/platform/src/components/AssociationsToolkit/components/layout.tsx b/apps/platform/src/components/AssociationsToolkit/components/layout.tsx index 02e76a168..29241bc9a 100644 --- a/apps/platform/src/components/AssociationsToolkit/components/layout.tsx +++ b/apps/platform/src/components/AssociationsToolkit/components/layout.tsx @@ -71,6 +71,7 @@ export const RowContainer = styled("div", { zIndex: rowExpanded ? "99 !important" : "initial", backgroundColor: rowExpanded ? grey[300] : "initial", border: rowExpanded ? `1px solid ${grey[400]}` : "none", + borderBottom: rowExpanded ? `none` : "none", "&:hover": { backgroundColor: grey[300], }, diff --git a/apps/platform/src/components/AssociationsToolkit/context/AssociationsFocusContext.tsx b/apps/platform/src/components/AssociationsToolkit/context/AssociationsFocusContext.tsx index 7415215b3..756a04a1b 100644 --- a/apps/platform/src/components/AssociationsToolkit/context/AssociationsFocusContext.tsx +++ b/apps/platform/src/components/AssociationsToolkit/context/AssociationsFocusContext.tsx @@ -160,6 +160,8 @@ function focusReducer(focusState: FocusState, action: FocusAction): FocusState { // same row active -> update active section acc.push({ ...element, + interactorsRow: null, + interactorsSection: null, section: action.focus.section, }); return acc; @@ -170,6 +172,8 @@ function focusReducer(focusState: FocusState, action: FocusAction): FocusState { acc.push({ ...element, section: null, + interactorsSection: null, + interactorsRow: null, }); return acc; } @@ -308,6 +312,7 @@ function focusReducer(focusState: FocusState, action: FocusAction): FocusState { ...element, interactorsRow: action.focus.interactorsRow, interactorsSection: action.focus.section, + section: null, }); return acc; } @@ -320,8 +325,6 @@ function focusReducer(focusState: FocusState, action: FocusAction): FocusState { interactorsRow: null, interactorsSection: null, }); - } else { - acc.push({ ...element }); } return acc; } else {