Skip to content

Commit

Permalink
feat: dataset about page with provided markdown
Browse files Browse the repository at this point in the history
  • Loading branch information
davidlougheed committed Jan 17, 2024
1 parent 90fc29a commit 1ab0170
Show file tree
Hide file tree
Showing 20 changed files with 241 additions and 33 deletions.
5 changes: 0 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
~$*
/.idea
/data/*
!/data/.gitkeep
!/data/assemblies
!/data/otherData
!/data/ucsc.other-tracks.txt
/input-files/*.csv
!/input-files/flu-infection-gene-peaks.csv
/config.js
Expand Down
6 changes: 6 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"clsx": "^1.2.1",
"d3-quadtree": "^3.0.1",
"d3-scale": "^4.0.2",
"dompurify": "^3.0.6",
"font-awesome": "^4.7.0",
"igv": "^2.15.11",
"memoize-one": "^6.0.0",
Expand Down
16 changes: 10 additions & 6 deletions client/src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import TermsModal from "./TermsModal";
import ContactModal from "./ContactModal";
import AboutPage from "./pages/AboutPage";
import ProtectedPageContainer from "./pages/ProtectedPageContainer";
import DatasetAboutPage from "./pages/DatasetAboutPage";
import OverviewPage from "./pages/OverviewPage";
import ExplorePage from "./pages/ExplorePage";
import DatasetsPage from "./pages/DatasetsPage";
Expand Down Expand Up @@ -41,13 +42,14 @@ const RoutedApp = () => {
const navigateAbout = useCallback(() => navigate("/about"), [navigate]);
const navigateDatasets = useCallback(() => navigate("/datasets"), [navigate]);
// TODO: remember chrom and assay:
const navigateOverview = useCallback(() => navigate("/overview"), [navigate]);
const navigateDatasetAbout = useCallback(() => navigate("/dataset/about"), [navigate]);
const navigateOverview = useCallback(() => navigate("/dataset/overview"), [navigate]);
const navigateExplore = useCallback(() => {
if (location.pathname.startsWith("/explore")) return;
if (location.pathname.startsWith("/dataset/explore")) return;
if (chrom && position) {
navigate(`/explore/locus/${chrom}/${position}`);
navigate(`/dataset/explore/locus/${chrom}/${position}`);
} else {
navigate("/explore");
navigate("/dataset/explore");
}
}, [location.pathname, chrom, position, navigate]);
const navigateFAQ = () => navigate("/faq");
Expand Down Expand Up @@ -92,6 +94,7 @@ const RoutedApp = () => {

<Header onAbout={navigateAbout}
onDatasets={navigateDatasets}
onDatasetAbout={navigateDatasetAbout}
onOverview={navigateOverview}
onExplore={navigateExplore}
onFAQ={navigateFAQ}
Expand All @@ -114,10 +117,11 @@ const App = () => (
<Route index={true} element={<Navigate to="/about" replace={true} />} />
<Route path="about" element={<AboutPage />} />
<Route path="datasets" element={<DatasetsPage />} />
<Route path="overview" element={<ProtectedPageContainer>
<Route path="dataset/about" element={<DatasetAboutPage />} />
<Route path="dataset/overview" element={<ProtectedPageContainer>
<OverviewPage />
</ProtectedPageContainer>} />
<Route path="explore" element={<ProtectedPageContainer>
<Route path="dataset/explore" element={<ProtectedPageContainer>
<ExplorePage />
</ProtectedPageContainer>}>
<Route index={true} element={<PeakResults />} />
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ const Controls = ({toggleHelp}) => {
// The item assay is the tab with the most significant result - which will be
// selected first by nature of ordering, thus leading the user to the most interesting
// detail from the autocomplete.
navigate(`/explore/locus/${chrom}/${position}/${item.assay}`, {replace: true});
navigate(`/dataset/explore/locus/${chrom}/${position}/${item.assay}`, {replace: true});
changePosition(position);
dispatch(doSearch());
setDidFirstSearch(true);
Expand Down Expand Up @@ -192,7 +192,7 @@ const Controls = ({toggleHelp}) => {

const onClickSearch = useCallback(() => {
if (!chrom || !position) return;
navigate(`/explore/locus/${chrom}/${position}`, {replace: true});
navigate(`/dataset/explore/locus/${chrom}/${position}`, {replace: true});
dispatch(doSearch());
setDidFirstSearch(true);
}, [navigate, chrom, position]);
Expand Down
9 changes: 5 additions & 4 deletions client/src/components/Footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ const Footer = ({/*onContact, */onTerms}) => (
</div>
<nav className="Footer__nav">
<ul>
<li><Link to="/about">About</Link></li>
<li><Link to="/datasets">Datasets</Link></li>
<li><Link to="/overview">Overview</Link></li>
<li><Link to="/explore">Explore</Link></li>
{/*<li><Link to="/datasets">Datasets</Link></li>*/}
<li><Link to="/dataset/about">About Dataset</Link></li>
<li><Link to="/dataset/overview">Overview</Link></li>
<li><Link to="/dataset/explore">Explore</Link></li>
<li><Link to="/about">About EpiVar</Link></li>
<li><a href="#" onClick={onTerms}>Terms of Use</a></li>
</ul>
</nav>
Expand Down
23 changes: 14 additions & 9 deletions client/src/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import Icon from "./Icon";

import {SITE_SUBTITLE, SITE_TITLE} from "../constants/app";

export default function Header({children, onAbout, onDatasets, onOverview, onExplore, onFAQ/*, onContact*/}) {
export default function Header({children, onAbout, /*onDatasets, */onDatasetAbout, onOverview, onExplore, onFAQ,
/*, onContact*/}) {
const location = useLocation();
const navigate = useNavigate();

Expand Down Expand Up @@ -39,20 +40,24 @@ export default function Header({children, onAbout, onDatasets, onOverview, onExp
</div>
</div>
<div className="Header__links">
<Button color="link"
className={location.pathname.startsWith("/about") ? "active" : ""}
onClick={onAbout}><Icon name="people-fill" bootstrap={true} />About</Button>
<Button color="link"
className={location.pathname.startsWith("/datasets") ? "active" : ""}
onClick={onDatasets}><Icon name="table" bootstrap={true} />Datasets</Button>
{/*<Button color="link"*/}
{/* className={location.pathname.startsWith("/datasets") ? "active" : ""}*/}
{/* onClick={onDatasets}><Icon name="table" bootstrap={true} />Datasets</Button>*/}
<div className="Header__highlight_group">
<Button color="link"
className={location.pathname.startsWith("/overview") ? "active" : ""}
className={location.pathname.startsWith("/dataset/about") ? "active" : ""}
onClick={onDatasetAbout}>
<Icon name="info-circle" bootstrap={true}/>About</Button>
<Button color="link"
className={location.pathname.startsWith("/dataset/overview") ? "active" : ""}
onClick={onOverview}><Icon name="graph-up" bootstrap={true} />Overview</Button>
<Button color="link"
className={"highlight" + (location.pathname.startsWith("/explore") ? " active" : "")}
className={"highlight" + (location.pathname.startsWith("/dataset/explore") ? " active" : "")}
onClick={onExplore}><Icon name="search" bootstrap={true} />Explore</Button>
</div>
<Button color="link"
className={location.pathname.startsWith("/about") ? "active" : ""}
onClick={onAbout}><Icon name="people-fill" bootstrap={true} />About EpiVar</Button>
<Button color="link"
className={location.pathname.startsWith("/faq") ? "active" : ""}
onClick={onFAQ}><Icon name="question-circle" bootstrap={true} />FAQ</Button>
Expand Down
7 changes: 4 additions & 3 deletions client/src/components/PeakResults.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ const PeakResults = () => {

if (activeAssay && !(activeAssay in peaksByAssay) && peaksLoaded) {
// Assay isn't valid for the position in question
navigate(`/explore/locus/${chrom}/${position}` +
navigate(`/dataset/explore/locus/${chrom}/${position}` +
(assaysWithFeatures.length ? `/${assays[0]}` : ""), {replace: true});
} else if (!activeAssay && assaysWithFeatures.length && peaksLoaded) {
navigate(`/explore/locus/${chrom}/${position}/${assaysWithFeatures[0]}`, {replace: true});
navigate(`/dataset/explore/locus/${chrom}/${position}/${assaysWithFeatures[0]}`, {replace: true});
}
}, [activeAssay, chrom, position, peaksLoaded]);

Expand Down Expand Up @@ -87,7 +87,8 @@ const PeakResults = () => {
return <NavItem key={assay}>
<NavLink
className={cx({active: activeAssay === assay})}
onClick={() => nPeaks && navigate(`/explore/locus/${chrom}/${position}/${assay}`, {replace: true})}
onClick={() =>
nPeaks && navigate(`/dataset/explore/locus/${chrom}/${position}/${assay}`, {replace: true})}
disabled={!nPeaks}
aria-disabled={true}
>
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/pages/AboutPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const AboutPage = () => {
the data.
</p>
<p>
We have also built a <Link to="/overview" style={{fontWeight: "bold"}}>browser tool</Link> that allows
We have also built a <Link to="/dataset/overview" style={{fontWeight: "bold"}}>browser tool</Link> that allows
navigation of these rich datasets by condition, ancestry and, importantly, haplotype. This allows an in-depth
exploration of the quantitative trait loci and other key results reported in the studies above. Using this
tool requires a simple terms-of-use agreement to ensure data privacy conditions are respected.
Expand Down
30 changes: 30 additions & 0 deletions client/src/components/pages/DatasetAboutPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, {useEffect, useMemo} from "react";
import {useSelector} from "react-redux";
import {useLocation} from "react-router-dom";
import {Container} from "reactstrap";

import * as DOMPurify from "dompurify";

const DatasetAboutPage = () => {
const location = useLocation();

useEffect(() => {
if (!location.hash) return;
const element = document.querySelector(location.hash);
if (!element) return;
element.scrollIntoView();
}, [location]);

// noinspection JSUnresolvedReference
/** @type string */
const datasetAboutContent = useSelector((state) => state.dataset.data?.aboutContent ?? "<em>Loading...</em>");
const sanitizedHTMLContent = useMemo(
() => ({__html: DOMPurify.sanitize(datasetAboutContent, {USE_PROFILES: {html: true}})}),
[datasetAboutContent]);

return <Container className="Page">
<div dangerouslySetInnerHTML={sanitizedHTMLContent} />
</Container>;
};

export default DatasetAboutPage;
2 changes: 1 addition & 1 deletion client/src/components/pages/DatasetsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const DatasetsPage = () => {
Genomic tracks by condition and ancestry are available <a href="#" onClick={openTracks}>here</a>.
</p>
<p>
We constructed <Link to="/overview">a versatile QTL browser</Link>, which allows users to explore and
We constructed <Link to="/dataset/overview">a versatile QTL browser</Link>, which allows users to explore and
visualize mapped QTLs for gene expression, chromatin accessibility, histone modifications and DNA methylation.
</p>
</Col>
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/pages/OverviewPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ const OverviewPage = () => {
onPointClick={peak => {
if (!dispatch) return;
const snp = peak[SNP_PROP];
navigate(`/explore/locus/rsID/${snp}/${assay}`);
navigate(`/dataset/explore/locus/rsID/${snp}/${assay}`);
dispatch(setChrom("rsID"));
dispatch(setPosition(snp));
dispatch(doSearch());
Expand Down
5 changes: 5 additions & 0 deletions data/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*
!about.md
!assemblies
!otherData
!ucsc.other-tracks.txt
Empty file removed data/.gitkeep
Empty file.
3 changes: 3 additions & 0 deletions data/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Replace me

This is an example dataset `about.md` file for an EpiVar node.
4 changes: 4 additions & 0 deletions envConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const getPrefixedEnvVar = (varName, defaultValue = undefined) => {
// - This is the application data directory
const DATA_DIR = path.join(__dirname, "./data");

// - About Markdown content
const ABOUT_MD_PATH = path.join(DATA_DIR, "about.md");

// - Static tracks to put in UCSC track hub. TODO: make this dataset-specific
const STATIC_TRACKS_PATH = path.join(DATA_DIR, "ucsc.other-tracks.txt");

Expand Down Expand Up @@ -79,6 +82,7 @@ const PLOT_MANHATTAN_BIN_SIZE = parseInt(getPrefixedEnvVar("MANHATTAN_BIN_SIZE",
module.exports = {
// Paths and data locations
DATA_DIR,
ABOUT_MD_PATH,
STATIC_TRACKS_PATH,
TRACK_METADATA_PATH,
INPUT_FILES_DIR,
Expand Down
Loading

0 comments on commit 1ab0170

Please sign in to comment.