Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f0677d3
Initial commit on decoupling tabs in the experiment page
upendrakumbham Dec 12, 2023
a21e6ee
Merge branch 'develop' into bugfix/decouple-experiment-page-tabs-and-…
upendrakumbham Dec 12, 2023
7a48932
Add multiple ternary conditional operator
upendrakumbham Jan 9, 2024
a071970
Merge branch 'develop' into bugfix/decouple-experiment-page-tabs-and-…
upendrakumbham Jan 9, 2024
aa55ced
Improved version of code after a tweak of tab conditions
upendrakumbham Jan 17, 2024
585972d
Add fubctions to validate tabs and it's props
upendrakumbham Jan 30, 2024
25ef163
Remove compilation errors and improve functions
upendrakumbham Feb 2, 2024
13e7ee2
Remove unused code and improve function
upendrakumbham Feb 9, 2024
532389c
remove hardcode strings and reuse code
upendrakumbham Feb 19, 2024
1f9aa46
Add tabtype 'resources' conditional check
upendrakumbham Feb 19, 2024
2c05e1a
Add empty object check and null, undefined function and update tab va…
upendrakumbham Feb 19, 2024
ca946ac
Fix camel casing in the function
upendrakumbham Feb 19, 2024
ea37496
Initiate tabTypeComponent = []; before return statement to clear data
upendrakumbham Jun 6, 2024
fcaab7c
Remove log messages
upendrakumbham Jun 6, 2024
05d2fb2
Improved code by removing if, else conditions & removed redundant code
upendrakumbham Jun 7, 2024
35bceb9
Merge branch 'develop' into bugfix/decouple-experiment-page-tabs-and-…
upendrakumbham Jun 7, 2024
99088cf
Move all helper functions to tabConfig.js file as part of ExperiemntP…
upendrakumbham Jun 10, 2024
b1cf7e5
Move PropTypes to propTypes.js file as part of ExperiemntPageRouter.j…
upendrakumbham Jun 10, 2024
5eaf719
Improved file
upendrakumbham Jun 10, 2024
dcf06f8
Add validation fields (common & specific)for the tabs
upendrakumbham Jun 26, 2024
e84663d
Add validations for tabs and common props
upendrakumbham Sep 4, 2024
08588ac
Remove renamed file
upendrakumbham Sep 4, 2024
bef7792
Merge branch 'develop' into bugfix/decouple-experiment-page-tabs-and-…
upendrakumbham Sep 4, 2024
a60205f
result tab validations
upendrakumbham Sep 4, 2024
53c0ce8
conflict resolved html demo page update
upendrakumbham Sep 4, 2024
7189295
add a suggesterEndpoint validation to the result tab
upendrakumbham Sep 5, 2024
d4179e1
add experiment-design tab validations
upendrakumbham Sep 5, 2024
4d3abc1
Add validation attributes to the 'Supplementary-information' and 'Dow…
upendrakumbham Sep 5, 2024
bf01724
Common validations code improvements
upendrakumbham Sep 6, 2024
21731ac
Add inner tab validations and make it result tab enablement depends o…
upendrakumbham Sep 9, 2024
865c176
Update TabConfig
upendrakumbham Sep 9, 2024
fea148e
Refactor a function name
upendrakumbham Sep 9, 2024
707dd79
Improve cell plots tab validations function
upendrakumbham Sep 9, 2024
0473eeb
Improve cell plots tab and marker genes tab validations
upendrakumbham Sep 9, 2024
a690dfc
Add backend ksWithMarkerGenes attribute payload for the marker genes …
upendrakumbham Sep 9, 2024
4ef6772
Remove console.log messages and ; to make code consistent
upendrakumbham Sep 10, 2024
10a0f14
Made code format changes to make code consitent
upendrakumbham Sep 10, 2024
76ed29e
Delete propTypes.js file
upendrakumbham Sep 11, 2024
f9a1240
Refactor variable name
upendrakumbham Sep 11, 2024
2887bfb
Merge branch 'develop' into bugfix/decouple-experiment-page-tabs-and-…
upendrakumbham Sep 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,100 changes: 1,283 additions & 817 deletions app/src/main/javascript/bundles/atlas-information-banner/package-lock.json

Large diffs are not rendered by default.

5,594 changes: 3,653 additions & 1,941 deletions app/src/main/javascript/bundles/cell-type-wheel-heatmap/package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
name: 'Results',
props: {
ks: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
ksWithMarkerGenes: [10, 13, 16, 21, 34, 42, 52, 63, 7],
metadata: [
{
value: `inferred cell type - authors labels`,
Expand Down Expand Up @@ -326,7 +327,7 @@
];

experimentPageDemo.render({
atlasUrl: 'http://localhost:8080/gxa/sc/',
atlasUrl: 'https://wwwdev.ebi.ac.uk/gxa/sc/',
content: {
experimentAccession: 'E-MTAB-5061',
experimentType: 'SINGLE_CELL_RNASEQ_MRNA_BASELINE',
Expand Down
5,205 changes: 2,504 additions & 2,701 deletions app/src/main/javascript/bundles/experiment-page/package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import { BrowserRouter, Route, Redirect, Switch, NavLink, withRouter } from 'react-router-dom'

Expand All @@ -8,132 +8,221 @@ import TSnePlotViewRoute from './TSnePlotViewRoute'
import ExperimentDesignRoute from './ExperimentDesignRoute'
import SupplementaryInformationRoute from './SupplementaryInformationRoute'
import DownloadsRoute from './DownloadsRoute'
import {isEmptyArray, tabCommonValidations, tabValidations} from "./TabConfig"

const RoutePropTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
match: PropTypes.object.isRequired,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clean the code and make this file smaller, I would externalise all the proptypes to another file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you group together the code parts that belongs to PropTypes?
Thanks

location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
}

const TabCommonPropTypes = {
atlasUrl: PropTypes.string.isRequired,
experimentAccession: PropTypes.string.isRequired,
species: PropTypes.string.isRequired,
accessKey: PropTypes.string,
resourcesUrl: PropTypes.string
atlasUrl: PropTypes.string.isRequired,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You already externalised the RoutePropTypes and TabCommonPropTypes, but forgot to remove from here.

experimentAccession: PropTypes.string.isRequired,
species: PropTypes.string.isRequired,
accessKey: PropTypes.string,
resourcesUrl: PropTypes.string
}

// What component each tab type should render, coupled to ExperimentController.java
const tabTypeComponent = {
'results' : TSnePlotViewRoute,
'experiment-design' : ExperimentDesignRoute,
'supplementary-information' : SupplementaryInformationRoute,
'downloads' : DownloadsRoute
'results' : TSnePlotViewRoute,
'experiment-design' : ExperimentDesignRoute,
'supplementary-information' : SupplementaryInformationRoute,
'downloads' : DownloadsRoute
}

const TopRibbon = ({tabs, routeProps}) =>
<ul className={`tabs`}>
{
tabs.map((tab) =>
<li title={tab.name} key={tab.type} className={`tabs-title`}>
<NavLink to={{pathname:`/${tab.type}`, search: routeProps.location.search, hash: routeProps.location.hash}}
activeClassName={`active`}>
{tab.name}
</NavLink>
</li>
)}
</ul>
function shouldRenderTab(tab, commonProps) {
const commonRequiredProps = tabCommonValidations.get(tab.type)
let shouldRender = true

if (commonRequiredProps != null) {
commonRequiredProps.some(commonProp => {
const propValue = commonProps.valueOf(commonProp)
if (propValue === 'undefined' || propValue == '' || propValue == null) {
console.log(`${tab.type} data missing the required value for the attribute ${commonProp}`)
shouldRender = false
return false
}
})
}

const requiredProps = tabValidations.get(tab.type)
const tabProps = tab.props

if (requiredProps != null) {
requiredProps.forEach(requiredProp => {
// Check if property requires nested object validation
if (requiredProp.includes('.')) {
const splitProps = requiredProp.split('.')
splitProps.forEach(splitProp => {

let table = []
let tableHeader = []
let tableData = []

if (isEmptyArray(table)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you just defined table as an empty array: [] this should be always true.
Please remove this line.
Thanks

table = tabProps[splitProp] || []
if (table.length == 0) {
console.log(`${tab.type}: table doesn't have data`)
shouldRender = false
return false // Early return on failure
}
}

if (isEmptyArray(tableHeader)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same as with the table var.
As you just defined tableHeader as an empty array: [] this should be always true.
Please remove this line.
Thanks

tableHeader = table[splitProp] || []
if (tableHeader.length == 0) {
console.log(tab.type + ":" + " table headers doesn't have data")
shouldRender = false
return false
}
}

if (isEmptyArray(tableData)) {
tableData = tableHeader[splitProp]
if (tableData.length == 0) {
console.log(tab.type + ":" + " table data doesn't have")
shouldRender = false
return false
}
}

})
return shouldRender
}
})
}
return shouldRender
}

const TopRibbon = ({tabs, routeProps, commonProps}) =>
<ul className={`tabs`}>
{
tabs.map((tab) => {
if(shouldRenderTab(tab, commonProps) === true) {
return <li title={tab.name} key={tab.type} className={`tabs-title`}>
<NavLink to={{
pathname: `/${tab.type}`,
search: routeProps.location.search,
hash: routeProps.location.hash
}}
activeClassName={`active`}>
{tab.name}
</NavLink>
</li>
}
}
)}
</ul>

TopRibbon.propTypes = {
tabs: PropTypes.arrayOf(PropTypes.shape({
type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
props: PropTypes.object
})).isRequired,
routeProps: PropTypes.shape(RoutePropTypes)
tabs: PropTypes.arrayOf(PropTypes.shape({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move all the propTypes from this class to the propTypes.js file.

type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
props: PropTypes.object
})).isRequired,
routeProps: PropTypes.shape(RoutePropTypes)
}


const TabContent = ({type, tabProps, commonProps, routeProps}) => {
// Pass in the search from location
const Tab = tabTypeComponent[type]
const TabContent = ({type, tabProps, commonProps, routeProps, resultTabView}) => {
// Pass in the search from location
const Tab = tabTypeComponent[type]

return (
Tab ? <Tab {...tabProps} {...commonProps} {...routeProps}/> : null
)
return (
Tab ? <Tab {...tabProps} {...commonProps} {...routeProps} enableView={resultTabView} /> : null
)
}

TabContent.propTypes = {
type: PropTypes.string.isRequired,
tabProps: PropTypes.object,
commonProps: PropTypes.shape(TabCommonPropTypes),
routeProps: PropTypes.shape(RoutePropTypes)
type: PropTypes.string.isRequired,
tabProps: PropTypes.object,
commonProps: PropTypes.shape(TabCommonPropTypes),
routeProps: PropTypes.shape(RoutePropTypes),
resultTabView : PropTypes.func
}

const RedirectWithSearchAndHash = (props) =>
<Redirect to={{ pathname: props.pathname, search: props.location.search, hash: props.location.hash}} />
<Redirect to={{ pathname: props.pathname, search: props.location.search, hash: props.location.hash}} />

RedirectWithSearchAndHash.propTypes = {
pathname: PropTypes.string.isRequired,
location: PropTypes.shape({
search: PropTypes.string.isRequired,
hash: PropTypes.string.isRequired
}).isRequired
pathname: PropTypes.string.isRequired,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proptypes are all over this JS file.
As I already mentioned, I would externalise them to a separate file and import them into this one.
That would make this file more clear.
What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you, I will try to do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proptypes are all over this JS file.
As I already mentioned, I would externalise them to a separate file and import them into this one.
That would make this file more clear.
What do you think?

This one is fixed. Please have a look.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what you meant by This one is fixed. Sadly nothing has changed here.

location: PropTypes.shape({
search: PropTypes.string.isRequired,
hash: PropTypes.string.isRequired
}).isRequired
}

const RedirectWithLocation = withRouter(RedirectWithSearchAndHash)

const ExperimentPageRouter = ({atlasUrl, resourcesUrl, experimentAccession, species, accessKey, tabs}) => {
const tabCommonProps = {
atlasUrl,
resourcesUrl,
experimentAccession,
species,
accessKey
}

return (
<BrowserRouter
basename={URI(`experiments/${experimentAccession}`, URI(atlasUrl).path()).toString()}>
<div>
<Route
path={`/`}
render={
(routeProps) =>
<TopRibbon
tabs={tabs}
routeProps={routeProps} />
} />
<Switch>
{
tabs.map((tab) =>
<Route
key={tab.type}
path={`/${tab.type}`}
render={
(routeProps) =>
<TabContent
type={tab.type}
tabProps={tab.props}
commonProps={tabCommonProps}
routeProps={routeProps} />
} />
)
}
<RedirectWithLocation pathname={`/${tabs[0].type}`} />
</Switch>
</div>
</BrowserRouter>
)

const [enableResultTab, setEnableResultTab] = useState(false)

let resultTabView = (resultTabView) => {
if(resultTabView) {
setEnableResultTab(true)
}
}

const tabCommonProps = {
atlasUrl,
resourcesUrl,
experimentAccession,
species,
accessKey
}

return (
<BrowserRouter
basename={URI(`experiments/${experimentAccession}`, URI(atlasUrl).path()).toString()}>
<div>
<Route
path={`/`}
render={
(routeProps) =>
<TopRibbon
tabs={tabs}
routeProps={routeProps}
commonProps={tabCommonProps}
/>
} />
<Switch>
{
tabs.map((tab) =>
{
if(shouldRenderTab(tab, tabCommonProps)) {
return <Route
key={tab.type}
path={`/${tab.type}`}
render={
(routeProps) =>
<TabContent
type={tab.type}
tabProps={tab.props}
commonProps={tabCommonProps}
routeProps={routeProps}
resultTabView={resultTabView}
/>
}/>
}
})
}
<RedirectWithLocation pathname={`/${tabs[0].type}`} />
</Switch>
</div>
</BrowserRouter>
)
}

ExperimentPageRouter.propTypes = {
...TabCommonPropTypes,
tabs: PropTypes.arrayOf(PropTypes.shape({
type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
props: PropTypes.object.isRequired
})).isRequired
...TabCommonPropTypes,
tabs: PropTypes.arrayOf(PropTypes.shape({
type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
props: PropTypes.object.isRequired
})).isRequired
}

export default ExperimentPageRouter
export default ExperimentPageRouter
Loading