Skip to content

Commit

Permalink
Merge branch 'develop' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
rlreamy authored Aug 22, 2023
2 parents d665e24 + 3eae180 commit 7b6a6c1
Show file tree
Hide file tree
Showing 18 changed files with 4,272 additions and 722 deletions.
4,230 changes: 3,603 additions & 627 deletions package-lock.json

Large diffs are not rendered by default.

28 changes: 16 additions & 12 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import FileListContainer from "./components/Repository/FileListContainer";
import packagejson from '../package.json';
import AppSearchAPIConnector from "@elastic/search-ui-app-search-connector";
import { SearchProvider } from "@elastic/react-search-ui";
import ReportCard from './components/ReportCard/ReportCard';

const cacheStore = window.sessionStorage.getItem('hyrda-redux-store');
const initialState = cacheStore ? JSON.parse(cacheStore) : loadedState;
Expand Down Expand Up @@ -107,8 +108,10 @@ const searchConfig = {
}
},
initialState: {
resultsPerPage: 1000
resultsPerPage: 20,
current: 1
},
trackUrlState: true,
alwaysSearchOnInitialLoad: true
}

Expand All @@ -121,17 +124,18 @@ class App extends Component {
return (
<Provider store={store}>
<SearchProvider config={searchConfig}>
<BrowserRouter history={history} basename={packagejson.baseURL}>
<ErrorBoundaryContainer>
<NavBar app='atlas' />
<Switch>
<Route exact path="/" component={FileListContainer} store={store} />
<Route exact path="/oops" component={Oops} />
<Route path='*' component={NotFoundPage} />
</Switch>
<NavFooter app='atlas' />
</ErrorBoundaryContainer>
</BrowserRouter>
<BrowserRouter history={history} basename={packagejson.baseURL}>
<ErrorBoundaryContainer>
<NavBar app='atlas' />
<Switch>
<Route exact path="/" component={FileListContainer} store={store} />
<Route exact path="/report" component={ReportCard} store={store}/>
<Route exact path="/oops" component={Oops} />
<Route path='*' component={NotFoundPage} />
</Switch>
<NavFooter app='atlas' />
</ErrorBoundaryContainer>
</BrowserRouter>
</SearchProvider>
</Provider>
);
Expand Down
53 changes: 48 additions & 5 deletions src/actions/Clinical/clinicalDatasetAction.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,61 @@
import actionNames from '../actionNames'
import actionNames from '../actionNames';
import { mapSummaryKeysToPresentationStyle } from '../../helpers/dataHelper';
import { fetchParticipantClinicalDataset, fetchParticipantDataTypeCounts, fetchParticipantSummaryDataset, fetchParticipantTotalFileCount } from '../../helpers/Api';


export const fetchAndSetSummaryDatasets = (participant_id) => {
return async (dispatch) => {
let summaryDatasets = await fetchParticipantSummaryDataset(participant_id);
summaryDatasets = mapSummaryKeysToPresentationStyle(summaryDatasets);
dispatch(setSummaryDatasets(summaryDatasets));
}
}

export const setSummaryDatasets = (summaryDatasets) => {
return {
type: actionNames.SET_SUMMARY_DATASETS,
payload: summaryDatasets
type: actionNames.SET_SUMMARY_DATASETS,
payload: summaryDatasets
}
}

export const fetchAndSetClinicalDatasets = (participant_id) => {
return async (dispatch) => {
let clinicalDatasets = await fetchParticipantClinicalDataset(participant_id);
dispatch(setClinicalDatasets(clinicalDatasets));
}
}

export const setClinicalDatasets = (clinicalDatasets) => {
return {
type: actionNames.SET_CLINICAL_DATASETS,
payload: clinicalDatasets
type: actionNames.SET_CLINICAL_DATASETS,
payload: clinicalDatasets
}
}

export const fetchAndSetDataTypeFileCounts = (participant_id) => {
return async (dispatch) => {
let dataTypeFileCounts = await fetchParticipantDataTypeCounts(participant_id);
dispatch(setDataTypeFileCounts(dataTypeFileCounts));
}
}

export const setDataTypeFileCounts = (dataTypeFileCounts) => {
return {
type: actionNames.SET_DATA_TYPE_COUNTS,
payload: dataTypeFileCounts
}
}

export const fetchAndSetTotalFileCount = (participant_id) => {
return async (dispatch) => {
let totalFileCount = await fetchParticipantTotalFileCount(participant_id);
dispatch(setTotalFileCount(totalFileCount));
}
}

export const setTotalFileCount = (totalFileCount) => {
return {
type: actionNames.SET_TOTAL_FILE_COUNT,
payload: totalFileCount
}
}
7 changes: 7 additions & 0 deletions src/actions/Experimental/experimentalDatasetAction.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import actionNames from '../actionNames'
import {fetchParticipantExperimentCounts} from "../../helpers/Api";

export const fetchAndSetExperimentalDataCounts = (participant_id) => {
return async (dispatch) => {
let experimentalDataCounts = await fetchParticipantExperimentCounts(participant_id);
dispatch(setExperimentalDataCounts(experimentalDataCounts));
}
}

export const setExperimentalDataCounts = (experimentalDataCounts) => {
return {
Expand Down
3 changes: 2 additions & 1 deletion src/actions/actionNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ const actionNames = {
SET_SUMMARY_DATASETS: 'SET_SUMMARY_DATASETS',
SET_CLINICAL_DATASETS: 'SET_CLINICAL_DATASETS',
SET_EXPERIMENTAL_DATASETS: 'SET_EXPERIMENTAL_DATASETS',

SET_DATA_TYPE_COUNTS: 'SET_DATA_TYPE_COUNTS',
SET_TOTAL_FILE_COUNT: 'SET_TOTAL_FILE_COUNT'
};

export default actionNames;
201 changes: 201 additions & 0 deletions src/components/ReportCard/ReportCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import { Component } from 'react';
import { Col, Container, Row } from "reactstrap";
import '@devexpress/dx-react-grid-bootstrap4/dist/dx-react-grid-bootstrap4.css';
import { Grid, Table, TableColumnResizing, TableHeaderRow } from '@devexpress/dx-react-grid-bootstrap4';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faFile } from '@fortawesome/free-regular-svg-icons';
import { dataToTableConverter, experimentalDataConverter, fileCountsToTableConverter, mapClinicalKeysToPresentationStyle } from '../../helpers/dataHelper';

class ReportCard extends Component {
constructor(props) {
super(props);
this.state = {
summaryDataset: {},
totalFileCount: "",
experimentalDataCounts: {},
dataTypeFileCounts: [],
clinicalDataset: {}
}
}

componentDidMount() {
let sessionStorage = JSON.parse(window.sessionStorage.getItem('hydra-redux-store'));
if (sessionStorage === null || Object.keys(sessionStorage["summaryDatasets"]).length === 0) {
window.location.replace('/');
}
this.setState({
summaryDataset: sessionStorage["summaryDatasets"],
experimentalDataCounts: sessionStorage['experimentalDataCounts'],
dataTypeFileCounts: sessionStorage['dataTypeFileCounts']['repositoryDataTypes'],
clinicalDataset: (sessionStorage['clinicalDatasets']['clinicalData']) ? JSON.parse(sessionStorage['clinicalDatasets']['clinicalData']) : {},
totalFileCount: sessionStorage['totalFileCount'],
isLoaded: true
})
}

getTotalFileCountLink = () => {
return this.state.totalFileCount !== "" ? '/repository?filters[0][field]='
+ this.state.totalFileCount['linkInformation']['linkType']
+ '&filters[0][values][0]='
+ this.state.totalFileCount['linkInformation']['linkValue']
+ '&filters[0][type]=any' : "";
}

getDefaultColumnWidths = () => {
return [
{ columnName: 'key', width: 215 },
{ columnName: 'value', width: 180 },
]
};
getDefaultLinkColumnWidths = () => {
return [
{ columnName: 'Experimental Strategy', width: 380 },
{ columnName: 'Files', width: 30 },
]
};
getColumns = () => {
return [
{
name: 'key',
sortable: false,
hideable: false,
defaultHidden: false,
},
{
name: 'value',
sortable: false,
hideable: false,
defaultHidden: false,
},
];
};

formatLinkableCellKey = (row) => {
let key = row['key'];
return( key )
}

formatLinkableCellValue = (row) => {
let link = '/'
if (row.tool === 'spatial-viewer') {
link = '/' + row.tool + '?filters[0][field]=datatype&filters[0][values][0]=' + row.key + '&filters[0][type]=any&filters[1][field]=redcapid&filters[1][values][0]=' + this.state.summaryDataset['Participant ID'] + '&filters[1][type]=any'
} else if (row.tool === 'explorer') {
let dataType = '';
if (row.key.includes('Single-cell')) {
dataType = 'sc'
} else if (row.key.includes('Single-nuc')) {
dataType = 'sn'
} else if (row.key.includes('Regional')) {
dataType = 'regionalViz'
}
link = '/' + row.tool + '/dataViz?dataType=' + dataType
}

return (row['value'] > 0 ? <a className="p-0" href={link}>{row['value']}</a> : <span>{row['value']}</span>)
}

getExperimentalLinkableColumns = () => {
return [
{
name: 'Experimental Strategies',
sortable: false,
hideable: false,
defaultHidden: false,
getCellValue: row => this.formatLinkableCellKey(row)
},
{
name: 'Files',
sortable: false,
hideable: false,
defaultHidden: false,
getCellValue: row => <div style={{ textAlign: 'right' }}>{this.formatLinkableCellValue(row)}</div>
}
];
};

getRowSets = (dataset) => {
return experimentalDataConverter(dataset)
}

getRows = (dataset) => {
return dataToTableConverter(dataset)
}

render() {
return (
<div className='report-card ms-5 me-5'>
<Row className='pt-2'>
<Col className='report-col col-sm-12 col-md-8 col-lg-10'>
<Container className='container-max landing mb-4 rounded border p-3 pt-2 shadow-sm'>
<div className='report-header mb-3'>
Participant Summary
</div>
<Grid rows={this.getRows(this.state.summaryDataset)} columns={this.getColumns()}>
<Table />
<TableColumnResizing defaultColumnWidths={this.getDefaultColumnWidths()} />
</Grid>
</Container>
</Col>
<Col className='report-col col-sm-12 col-md-4 col-lg-2'>
<Container className='container-max landing mb-4 rounded border p-3 pt-2 shadow-sm'>
<Row>
<Col className=''>
Files
<div className='h3'>
<a href={this.getTotalFileCountLink()}>{this.state.totalFileCount['count']}</a>
</div>
</Col>
<Col className='text-end align-bottom h1'>
<FontAwesomeIcon
className="fas fa-file fa-light" icon={faFile} />
</Col>
</Row>
</Container>
</Col>
</Row>
<Row className=''>
<Col className='report-col col-sm-12 col-md-12 col-lg-6'>
<Container className='container-max landing mb-4 rounded border p-3 pt-2 shadow-sm' style={{ height: 'fit-content' }}>
<div className='report-header'>
File Counts by Data Type
</div>
<Grid rows={fileCountsToTableConverter(this.state.dataTypeFileCounts, this.state.summaryDataset['Participant ID'])} columns={this.getColumns()}>
<Table />
</Grid>
</Container>
</Col>
<Col className='report-col col-sm-12 col-md-12 col-lg-6'>
<Container className='container-max landing mb-4 rounded border p-3 pt-2 shadow-sm' style={{ height: 'fit-content' }}>
<div className='report-header'>
File Counts by Experimental Strategy
</div>
<Grid rows={this.getRowSets(this.state.experimentalDataCounts)} columns={this.getExperimentalLinkableColumns()}>
<Table columnExtensions={[{ columnName: 'Files', align: 'right' }]} />
<TableHeaderRow />
</Grid>
</Container>
</Col>
</Row>
<Row className=''>
<Col className='report-col col-12'>
<Container className='container-max landing mb-4 rounded border p-3 pt-2 shadow-sm' style={{ height: 'fit-content' }}>
<div className='report-header'>
Clinical
</div>
<Grid rows={this.getRows(mapClinicalKeysToPresentationStyle(this.state.clinicalDataset))} columns={this.getColumns()}>
<Table />
<TableColumnResizing defaultColumnWidths={[
{ columnName: 'key', width: 350 },
{ columnName: 'value', width: 500 },
]} />
</Grid>
</Container>
</Col>
</Row>
</div>
)
}
}


export default ReportCard;
Loading

0 comments on commit 7b6a6c1

Please sign in to comment.