Skip to content

Commit

Permalink
NickAkhmetov/HMP-474 Gene Detail Page - Summary/API hooks/supporting …
Browse files Browse the repository at this point in the history
…TS conversions (#3309)
  • Loading branch information
NickAkhmetov authored Nov 2, 2023
1 parent f349f04 commit 713bdfd
Show file tree
Hide file tree
Showing 38 changed files with 541 additions and 377 deletions.
1 change: 1 addition & 0 deletions CHANGELOG-HMP-474.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Update gene detail summary implementation.
1 change: 1 addition & 0 deletions context/app/default_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class DefaultConfig(object):
WORKSPACES_ENDPOINT = 'should-be-overridden'
WORKSPACES_WS_ENDPOINT = 'should-be-overridden'
USER_TEMPLATES_ENDPOINT = 'should-be-overriden'
UBKG_ENDPOINT = 'should-be-overridden'

SECRET_KEY = 'should-be-overridden'
APP_CLIENT_ID = 'should-be-overridden'
Expand Down
8 changes: 4 additions & 4 deletions context/app/routes_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,14 @@ def iframe_page(path):
)


@blueprint.route('/genes/<geneSymbol>')
def genes(geneSymbol):
@blueprint.route('/genes/<gene_symbol>')
def genes(gene_symbol):
flask_data = {
**get_default_flask_data(),
'geneSymbol': geneSymbol
'geneSymbol': gene_symbol
}
return render_template(
'base-pages/react-content.html',
title='genes',
title=gene_symbol,
flask_data=flask_data
)
1 change: 1 addition & 0 deletions context/app/static/js/components/Contexts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ interface AppContextType {
workspacesToken: string;
workspacesEndpoint: string;
userTemplatesEndpoint: string;
ubkgEndpoint: string;
[key: string]: unknown;
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { PropsWithChildren } from 'react';

import useEntityStore, { savedAlertStatus, editedAlertStatus, EntityStore } from 'js/stores/useEntityStore';
import TableOfContents from 'js/shared-styles/sections/TableOfContents';
import { getSections } from 'js/shared-styles/sections/TableOfContents/utils';
import { Content, FlexRow, StyledAlert } from './style';

const entityStoreSelector = (state: EntityStore) => ({
shouldDisplaySavedOrEditedAlert: state.shouldDisplaySavedOrEditedAlert,
setShouldDisplaySavedOrEditedAlert: state.setShouldDisplaySavedOrEditedAlert,
});

interface DetailLayoutProps extends PropsWithChildren {
sectionOrder: string[];
}

function DetailAlert() {
const { shouldDisplaySavedOrEditedAlert, setShouldDisplaySavedOrEditedAlert } = useEntityStore(entityStoreSelector);

if (shouldDisplaySavedOrEditedAlert === savedAlertStatus) {
return (
<StyledAlert severity="success" onClose={() => setShouldDisplaySavedOrEditedAlert(false)}>
Successfully added to My Saves List. All lists are currently stored on local storage and are not transferable
between devices.
</StyledAlert>
);
}

if (shouldDisplaySavedOrEditedAlert === editedAlertStatus) {
return (
<StyledAlert severity="success" onClose={() => setShouldDisplaySavedOrEditedAlert(false)}>
Successfully updated save status. All lists are currently stored on local storage and are not transferable
between devices.
</StyledAlert>
);
}
}

function DetailLayout({ sectionOrder, children }: DetailLayoutProps) {
// section hash must match section id in each component
const sections = new Map(getSections(sectionOrder));

return (
<>
<DetailAlert />
<FlexRow>
<TableOfContents items={[...sections.values()]} />
<Content>{children}</Content>
</FlexRow>
</>
);
}

export default DetailLayout;
14 changes: 0 additions & 14 deletions context/app/static/js/components/detailPage/style.js

This file was deleted.

17 changes: 17 additions & 0 deletions context/app/static/js/components/detailPage/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { styled } from '@mui/material/styles';
import { Alert } from 'js/shared-styles/alerts';
import MUIAlert from '@mui/material/Alert';
import { entityHeaderHeight } from 'js/components/detailPage/entityHeader/EntityHeader';
import Section, { baseOffset } from 'js/shared-styles/sections/Section';

// Using the `typeof MUIAlert` workaround here to avoid converting
// all of the `Alert` components to TS for now.
const DetailPageAlert = styled(Alert as typeof MUIAlert)(({ theme }) => ({
mb: theme.spacing(2),
})) as typeof MUIAlert;

const DetailPageSection = styled(Section)({
scrollMarginTop: `${baseOffset + entityHeaderHeight}px`,
});

export { DetailPageAlert, DetailPageSection };

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { PropsWithChildren, useEffect } from 'react';
import Typography from '@mui/material/Typography';
import { useInView } from 'react-intersection-observer';

import useEntityStore, { EntityStore } from 'js/stores/useEntityStore';
import InfoTooltipIcon from 'js/shared-styles/icons/TooltipIcon';
import { Stack } from '@mui/material';

const entityStoreSelector = (state: EntityStore) => state.setSummaryComponentObserver;

interface SummaryTitleProps extends PropsWithChildren {
iconTooltipText?: string;
}

function SummaryTitle({ children, iconTooltipText }: SummaryTitleProps) {
const setSummaryComponentObserver = useEntityStore(entityStoreSelector);

const { ref, inView, entry } = useInView({
/* Optional options */
threshold: 0,
initialInView: true,
});

useEffect(() => {
if (entry) {
setSummaryComponentObserver(inView, entry);
}
}, [setSummaryComponentObserver, entry, inView]);

return (
<Stack direction="row" alignItems="center">
<Typography variant="subtitle1" component="h1" color="primary" ref={ref}>
{children}
</Typography>
<InfoTooltipIcon iconTooltipText={iconTooltipText} />
</Stack>
);
}

export default SummaryTitle;
15 changes: 15 additions & 0 deletions context/app/static/js/components/genes/GenePageContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React, { PropsWithChildren, useMemo } from 'react';
import { createContext, useContext } from 'js/helpers/context';

interface GenePageContext {
geneSymbol: string;
}

const GenePageContext = createContext<GenePageContext>('GenePageContext');

export default function GenePageProvider({ children, geneSymbol }: PropsWithChildren<GenePageContext>) {
const value = useMemo(() => ({ geneSymbol }), [geneSymbol]);
return <GenePageContext.Provider value={value}>{children}</GenePageContext.Provider>;
}

export const useGenePageContext = () => useContext(GenePageContext);
37 changes: 37 additions & 0 deletions context/app/static/js/components/genes/GenePageTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';

import Skeleton from '@mui/material/Skeleton';
import Stack from '@mui/material/Stack';

import PageTitle from 'js/shared-styles/pages/PageTitle';

import { useGeneDetails, useGenePageContext } from './hooks';

function GeneSymbol() {
const { geneSymbol } = useGenePageContext();
const { data } = useGeneDetails();
if (!data) {
return geneSymbol.toUpperCase();
}
return data.approved_symbol;
}

function GeneName() {
const { data } = useGeneDetails();
if (!data) {
return <Skeleton variant="rounded" width={160} sx={{ display: 'inline-block' }} />;
}
return data.approved_name;
}

function GenePageTitle() {
return (
<PageTitle>
<Stack direction="row">
<GeneSymbol /> (<GeneName />)
</Stack>
</PageTitle>
);
}

export default GenePageTitle;
56 changes: 56 additions & 0 deletions context/app/static/js/components/genes/Summary/KnownReferences.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react';

import OutboundIconLink from 'js/shared-styles/Links/iconLinks/OutboundIconLink';
import hasKey from 'js/helpers/hasKey';
import { capitalizeString } from 'js/helpers/functions';

import { Skeleton } from '@mui/material';
import { useGeneDetails } from '../hooks';
import { ReferenceList } from './styles';

// Map reference sources to display names
// default to capitalizing the original source name if not found
const referenceMap = new Proxy<Record<string, string>>(
{
entrez: 'Entrez',
hugo: 'HUGO HGNC',
omim: 'OMIM',
uniprotkb: 'UniProt',
ensembl: 'Ensembl',
},
{
get: (target: object, prop: string) => (hasKey(target, prop) ? target[prop] : capitalizeString(prop)),
},
);

function ReferenceListContents() {
const { data } = useGeneDetails();
if (!data) {
return (
<>
<Skeleton width={100} />
<Skeleton width={120} />
<Skeleton width={80} />
</>
);
}
return (
<>
{data.references.map(({ url, source }) => (
<li key={source}>
<OutboundIconLink href={url}>{referenceMap[source]}</OutboundIconLink>
</li>
))}
</>
);
}

function KnownReferences() {
return (
<ReferenceList>
<ReferenceListContents />
</ReferenceList>
);
}

export default KnownReferences;
13 changes: 0 additions & 13 deletions context/app/static/js/components/genes/Summary/Summary.jsx

This file was deleted.

Loading

0 comments on commit 713bdfd

Please sign in to comment.