Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Open sidebar
ensembl-web
ensembl-client
Commits
ff75bed5
Unverified
Commit
ff75bed5
authored
Feb 10, 2021
by
Manoj Pandian Sakthivel
Committed by
GitHub
Feb 10, 2021
Browse files
Update Gene & Transcript drawer view to retrieve data from Thoas (#445)
parent
013213ed
Changes
54
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
596 additions
and
173 deletions
+596
-173
src/ensembl/src/content/app/browser/Browser.test.tsx
src/ensembl/src/content/app/browser/Browser.test.tsx
+16
-15
src/ensembl/src/content/app/browser/Browser.tsx
src/ensembl/src/content/app/browser/Browser.tsx
+24
-20
src/ensembl/src/content/app/browser/drawer/Drawer.scss
src/ensembl/src/content/app/browser/drawer/Drawer.scss
+0
-47
src/ensembl/src/content/app/browser/drawer/drawer-views/gene-summary/GeneSummary.scss
...browser/drawer/drawer-views/gene-summary/GeneSummary.scss
+47
-0
src/ensembl/src/content/app/browser/drawer/drawer-views/gene-summary/GeneSummary.tsx
.../browser/drawer/drawer-views/gene-summary/GeneSummary.tsx
+115
-11
src/ensembl/src/content/app/browser/drawer/drawer-views/track-details/TrackDetails.scss
...owser/drawer/drawer-views/track-details/TrackDetails.scss
+0
-24
src/ensembl/src/content/app/browser/drawer/drawer-views/transcript-summary/TranscriptSummary.scss
...er/drawer-views/transcript-summary/TranscriptSummary.scss
+85
-0
src/ensembl/src/content/app/browser/drawer/drawer-views/transcript-summary/TranscriptSummary.tsx
...wer/drawer-views/transcript-summary/TranscriptSummary.tsx
+291
-38
src/ensembl/src/content/app/browser/drawer/sampleData.ts
src/ensembl/src/content/app/browser/drawer/sampleData.ts
+1
-1
src/ensembl/src/content/app/entity-viewer/gene-view/GeneView.tsx
...embl/src/content/app/entity-viewer/gene-view/GeneView.tsx
+1
-1
src/ensembl/src/content/app/entity-viewer/gene-view/components/default-transcripts-list/DefaultTranscriptsList.tsx
...nents/default-transcripts-list/DefaultTranscriptsList.tsx
+2
-2
src/ensembl/src/content/app/entity-viewer/gene-view/components/default-transcripts-list/default-transcripts-list-item/DefaultTranscriptListItem.tsx
...fault-transcripts-list-item/DefaultTranscriptListItem.tsx
+2
-2
src/ensembl/src/content/app/entity-viewer/gene-view/components/default-transcripts-list/transcripts-list-item-info/TranscriptsListItemInfo.tsx
...st/transcripts-list-item-info/TranscriptsListItemInfo.tsx
+2
-2
src/ensembl/src/content/app/entity-viewer/gene-view/components/gene-function/GeneFunction.tsx
...iewer/gene-view/components/gene-function/GeneFunction.tsx
+1
-1
src/ensembl/src/content/app/entity-viewer/gene-view/components/gene-overview-image/GeneOverviewImage.tsx
...view/components/gene-overview-image/GeneOverviewImage.tsx
+1
-1
src/ensembl/src/content/app/entity-viewer/gene-view/components/gene-view-sidebar/external-references/GeneExternalReferences.tsx
...ew-sidebar/external-references/GeneExternalReferences.tsx
+3
-3
src/ensembl/src/content/app/entity-viewer/gene-view/components/gene-view-sidebar/overview/GeneOverview.tsx
...ew/components/gene-view-sidebar/overview/GeneOverview.tsx
+1
-1
src/ensembl/src/content/app/entity-viewer/gene-view/components/protein-domain-image/ProteinDomainImage.tsx
...ew/components/protein-domain-image/ProteinDomainImage.tsx
+1
-1
src/ensembl/src/content/app/entity-viewer/gene-view/components/protein-image/ProteinImage.tsx
...iewer/gene-view/components/protein-image/ProteinImage.tsx
+1
-1
src/ensembl/src/content/app/entity-viewer/gene-view/components/proteins-list/ProteinsList.tsx
...iewer/gene-view/components/proteins-list/ProteinsList.tsx
+2
-2
No files found.
src/ensembl/src/content/app/browser/Browser.test.tsx
View file @
ff75bed5
...
...
@@ -48,27 +48,28 @@ jest.mock('./drawer/Drawer', () => () => <div>Drawer</div>);
jest
.
mock
(
'
ensembl-genome-browser
'
,
()
=>
{
return
;
});
jest
.
mock
(
'
src/gql-client
'
,
()
=>
({
client
:
jest
.
fn
()
}));
const
defaultProps
:
BrowserProps
=
{
activeGenomeId
:
faker
.
lorem
.
words
(),
activeEnsObjectId
:
faker
.
lorem
.
words
(),
browserActivated
:
false
,
browserNavOpened
:
false
,
browserQueryParams
:
{},
chrLocation
:
createChrLocationValues
().
tupleValue
,
isDrawerOpened
:
false
,
isTrackPanelOpened
:
false
,
exampleEnsObjects
:
[],
toggleTrackPanel
:
jest
.
fn
(),
toggleDrawer
:
jest
.
fn
(),
viewportWidth
:
BreakpointWidth
.
DESKTOP
};
describe
(
'
<Browser />
'
,
()
=>
{
afterEach
(()
=>
{
jest
.
resetAllMocks
();
});
const
defaultProps
:
BrowserProps
=
{
activeGenomeId
:
faker
.
lorem
.
words
(),
activeEnsObjectId
:
faker
.
lorem
.
words
(),
browserActivated
:
false
,
browserNavOpened
:
false
,
browserQueryParams
:
{},
chrLocation
:
createChrLocationValues
().
tupleValue
,
isDrawerOpened
:
false
,
isTrackPanelOpened
:
false
,
exampleEnsObjects
:
[],
toggleTrackPanel
:
jest
.
fn
(),
toggleDrawer
:
jest
.
fn
(),
viewportWidth
:
BreakpointWidth
.
DESKTOP
};
const
wrappingComponent
=
(
props
:
any
)
=>
(
<
MemoryRouter
>
{
props
.
children
}
</
MemoryRouter
>
);
...
...
src/ensembl/src/content/app/browser/Browser.tsx
View file @
ff75bed5
...
...
@@ -15,11 +15,13 @@
*/
import
React
,
{
useEffect
}
from
'
react
'
;
import
{
ApolloProvider
}
from
'
@apollo/client
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
Link
}
from
'
react-router-dom
'
;
import
useBrowserRouting
from
'
./hooks/useBrowserRouting
'
;
import
{
client
}
from
'
src/gql-client
'
;
import
analyticsTracking
from
'
src/services/analytics-service
'
;
import
*
as
urlFor
from
'
src/shared/helpers/urlHelper
'
;
import
{
BreakpointWidth
}
from
'
src/global/globalConfig
'
;
...
...
@@ -117,26 +119,28 @@ export const Browser = (props: BrowserProps) => {
);
return
(
<
div
className
=
{
styles
.
browserInnerWrapper
}
>
<
BrowserAppBar
onSpeciesSelect
=
{
changeGenomeId
}
/>
{
props
.
browserQueryParams
.
focus
?
(
<
StandardAppLayout
mainContent
=
{
mainContent
}
sidebarContent
=
{
<
TrackPanel
/>
}
sidebarNavigation
=
{
<
TrackPanelTabs
/>
}
sidebarToolstripContent
=
{
<
TrackPanelBar
/>
}
onSidebarToggle
=
{
onSidebarToggle
}
topbarContent
=
{
<
BrowserBar
/>
}
isSidebarOpen
=
{
props
.
isTrackPanelOpened
}
isDrawerOpen
=
{
props
.
isDrawerOpened
}
drawerContent
=
{
<
Drawer
/>
}
onDrawerClose
=
{
toggleDrawer
}
viewportWidth
=
{
props
.
viewportWidth
}
/>
)
:
(
<
ExampleObjectLinks
{
...
props
}
/>
)
}
</
div
>
<
ApolloProvider
client
=
{
client
}
>
<
div
className
=
{
styles
.
browserInnerWrapper
}
>
<
BrowserAppBar
onSpeciesSelect
=
{
changeGenomeId
}
/>
{
props
.
browserQueryParams
.
focus
?
(
<
StandardAppLayout
mainContent
=
{
mainContent
}
sidebarContent
=
{
<
TrackPanel
/>
}
sidebarNavigation
=
{
<
TrackPanelTabs
/>
}
sidebarToolstripContent
=
{
<
TrackPanelBar
/>
}
onSidebarToggle
=
{
onSidebarToggle
}
topbarContent
=
{
<
BrowserBar
/>
}
isSidebarOpen
=
{
props
.
isTrackPanelOpened
}
isDrawerOpen
=
{
props
.
isDrawerOpened
}
drawerContent
=
{
<
Drawer
/>
}
onDrawerClose
=
{
toggleDrawer
}
viewportWidth
=
{
props
.
viewportWidth
}
/>
)
:
(
<
ExampleObjectLinks
{
...
props
}
/>
)
}
</
div
>
</
ApolloProvider
>
);
};
...
...
src/ensembl/src/content/app/browser/drawer/Drawer.scss
View file @
ff75bed5
...
...
@@ -5,50 +5,3 @@
overflow
:
auto
;
font-size
:
13px
;
}
.drawerView
{
overflow-y
:
auto
;
margin-top
:
10px
;
h2
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
text-align
:
center
;
}
p
{
margin
:
0px
;
}
.nextLine
{
display
:
block
;
margin-bottom
:
10px
;
}
.container
{
display
:
grid
;
grid-template-columns
:
100px
1fr
;
grid-column-gap
:
1em
;
grid-row-gap
:
1em
;
}
.label
{
font-weight
:
$light
;
text-align
:
right
;
}
.details
{
display
:
flex
;
text-align
:
left
;
}
.mainDetail
{
font-weight
:
$bold
;
}
.secondaryDetail
{
font-weight
:
$light
;
margin-left
:
10px
;
}
}
src/ensembl/src/content/app/browser/drawer/drawer-views/gene-summary/GeneSummary.scss
0 → 100644
View file @
ff75bed5
@import
'src/styles/common'
;
.row
{
display
:
grid
;
grid-template-columns
:
[
label
]
120px
[
value
]
auto
;
grid-column-gap
:
10px
;
margin-bottom
:
3px
;
.label
{
grid-column
:
label
;
font-weight
:
$light
;
text-align
:
right
;
}
.value
{
grid-column
:
value
;
}
}
.spaceAbove
{
margin-top
:
30px
;
}
.featureDetails
{
display
:
flex
;
align-items
:
center
;
white-space
:
nowrap
;
flex-wrap
:
nowrap
;
overflow
:
hidden
;
&
>
div
:not
(
:first-child
)
{
margin-left
:
30px
;
}
}
.featureSymbol
{
font-weight
:
$bold
;
}
.stableId
{
font-weight
:
$bold
;
}
.featureSymbol
+
.stableId
{
margin-left
:
12px
;
font-weight
:
$light
;
}
src/ensembl/src/content/app/browser/drawer/drawer-views/gene-summary/GeneSummary.tsx
View file @
ff75bed5
...
...
@@ -16,30 +16,134 @@
import
React
from
'
react
'
;
import
{
useSelector
}
from
'
react-redux
'
;
import
{
gql
,
useQuery
}
from
'
@apollo/client
'
;
import
{
getDisplayStableId
}
from
'
src/shared/state/ens-object/ensObjectHelpers
'
;
import
*
as
urlFor
from
'
src/shared/helpers/urlHelper
'
;
import
{
getFormattedLocation
}
from
'
src/shared/helpers/formatters/regionFormatter
'
;
import
{
getStrandDisplayName
}
from
'
src/shared/helpers/formatters/strandFormatter
'
;
import
{
buildFocusIdForUrl
,
getDisplayStableId
}
from
'
src/shared/state/ens-object/ensObjectHelpers
'
;
import
{
getBrowserActiveEnsObject
}
from
'
src/content/app/browser/browserSelectors
'
;
import
ViewInApp
from
'
src/shared/components/view-in-app/ViewInApp
'
;
import
{
EnsObjectGene
}
from
'
src/shared/state/ens-object/ensObjectTypes
'
;
import
{
Gene
as
GeneFromGraphql
}
from
'
src/shared/types/thoas/gene
'
;
import
styles
from
'
./GeneSummary.scss
'
;
const
GENE_QUERY
=
gql
`
query Gene($genomeId: String!, $geneId: String!) {
gene(byId: { genome_id: $genomeId, stable_id: $geneId }) {
alternative_symbols
name
stable_id
symbol
so_term
transcripts {
stable_id
}
slice {
strand {
code
value
}
location {
length
}
}
}
}
`
;
import
styles
from
'
src/content/app/browser/drawer/Drawer.scss
'
;
type
Gene
=
Required
<
Pick
<
GeneFromGraphql
,
|
'
stable_id
'
|
'
symbol
'
|
'
name
'
|
'
alternative_symbols
'
|
'
so_term
'
|
'
transcripts
'
|
'
slice
'
>
>
;
const
GeneSummary
=
()
=>
{
const
ensObject
=
useSelector
(
getBrowserActiveEnsObject
)
as
EnsObjectGene
;
const
ensObjectGene
=
useSelector
(
getBrowserActiveEnsObject
)
as
EnsObjectGene
;
const
{
data
,
loading
}
=
useQuery
<
{
gene
:
Gene
}
>
(
GENE_QUERY
,
{
variables
:
{
geneId
:
ensObjectGene
.
stable_id
,
genomeId
:
ensObjectGene
.
genome_id
},
skip
:
!
ensObjectGene
.
stable_id
});
if
(
loading
||
!
data
?.
gene
)
{
return
null
;
}
if
(
!
data
?.
gene
)
{
return
<
div
>
No data available
</
div
>;
}
const
{
gene
}
=
data
;
const
stableId
=
getDisplayStableId
(
gene
);
const
focusId
=
buildFocusIdForUrl
({
type
:
'
gene
'
,
objectId
:
gene
.
stable_id
as
string
});
const
entityViewerUrl
=
urlFor
.
entityViewer
({
genomeId
:
ensObjectGene
.
genome_id
,
entityId
:
focusId
});
return
(
<
div
className
=
{
styles
.
drawerView
}
>
<
div
className
=
{
styles
.
container
}
>
<
div
>
<
div
className
=
{
styles
.
row
}
>
<
div
className
=
{
styles
.
label
}
>
Gene
</
div
>
<
div
className
=
{
styles
.
details
}
>
<
span
className
=
{
styles
.
mainDetail
}
>
{
ensObject
.
label
}
</
span
>
<
div
className
=
{
styles
.
value
}
>
<
div
className
=
{
styles
.
featureDetails
}
>
{
gene
.
symbol
&&
(
<
span
className
=
{
styles
.
featureSymbol
}
>
{
gene
.
symbol
}
</
span
>
)
}
<
span
className
=
{
styles
.
stableId
}
>
{
stableId
}
</
span
>
<
div
>
{
gene
.
so_term
.
toLowerCase
()
}
</
div
>
<
div
>
{
getStrandDisplayName
(
gene
.
slice
.
strand
.
code
)
}
</
div
>
<
div
>
{
getFormattedLocation
(
ensObjectGene
.
location
)
}
</
div
>
</
div
>
</
div
>
</
div
>
<
div
className
=
{
`
${
styles
.
row
}
${
styles
.
spaceAbove
}
`
}
>
<
div
className
=
{
styles
.
label
}
>
Gene name
</
div
>
<
div
className
=
{
styles
.
value
}
>
{
gene
.
name
}
</
div
>
</
div
>
{
gene
.
alternative_symbols
.
length
>
0
&&
(
<
div
className
=
{
`
${
styles
.
row
}
${
styles
.
spaceAbove
}
`
}
>
<
div
className
=
{
styles
.
label
}
>
Synonyms
</
div
>
<
div
className
=
{
styles
.
value
}
>
{
gene
.
alternative_symbols
.
join
(
'
,
'
)
}
</
div
>
</
div
>
)
}
<
div
className
=
{
styles
.
label
}
>
Stable ID
</
div
>
<
div
className
=
{
styles
.
details
}
>
{
getDisplayStableId
(
ensObject
)
}
</
div
>
<
div
className
=
{
`
${
styles
.
row
}
${
styles
.
spaceAbove
}
`
}
>
<
div
className
=
{
styles
.
value
}
>
{
`
${
gene
.
transcripts
.
length
}
transcripts`
}
</
div
>
</
div
>
<
div
className
=
{
styles
.
label
}
>
Description
</
div
>
<
div
className
=
{
styles
.
details
}
>
{
ensObject
.
description
||
'
--
'
}
</
div
>
<
div
className
=
{
`
${
styles
.
row
}
${
styles
.
spaceAbove
}
`
}
>
<
div
className
=
{
styles
.
value
}
>
<
ViewInApp
links
=
{
{
entityViewer
:
entityViewerUrl
}
}
/>
</
div
>
</
div
>
</
div
>
);
...
...
src/ensembl/src/content/app/browser/drawer/drawer-views/track-details/TrackDetails.scss
View file @
ff75bed5
...
...
@@ -24,27 +24,3 @@
grid-column
:
value
;
}
}
.featureDetails
{
display
:
flex
;
align-items
:
center
;
white-space
:
nowrap
;
flex-wrap
:
nowrap
;
overflow
:
hidden
;
&
>
div
:not
(
:first-child
)
{
margin-left
:
30px
;
}
}
.featureSymbol
{
font-weight
:
$bold
;
}
.stableId
{
font-weight
:
$bold
;
}
.featureSymbol
+
.stableId
{
margin-left
:
12px
;
color
:
$dark-grey
;
font-weight
:
$light
;
}
src/ensembl/src/content/app/browser/drawer/drawer-views/transcript-summary/TranscriptSummary.scss
0 → 100644
View file @
ff75bed5
@import
'src/styles/common'
;
.row
{
display
:
grid
;
grid-template-columns
:
[
label
]
130px
[
value
]
auto
;
grid-column-gap
:
10px
;
margin-bottom
:
3px
;
.label
{
grid-column
:
label
;
font-weight
:
$light
;
text-align
:
right
;
font-size
:
12px
;
}
.value
{
grid-column
:
value
;
&
>
span
+
span
{
margin-left
:
10px
;
}
&
>
div
+
div
{
margin-top
:
3px
;
}
}
}
.spaceAbove
{
margin-top
:
30px
;
}
.lightText
{
font-weight
:
$light
;
}
.unit
{
font-weight
:
$light
;
font-size
:
12px
;
margin-left
:
5px
;
}
.value
.featureDetails
{
display
:
flex
;
align-items
:
center
;
white-space
:
nowrap
;
flex-wrap
:
nowrap
;
overflow
:
hidden
;
&
>
span
:not
(
:first-child
)
{
margin-left
:
30px
;
}
}
.featureSymbol
{
font-weight
:
$bold
;
}
.stableId
{
font-weight
:
$bold
;
}
.featureSymbol
+
.stableId
{
margin-left
:
12px
;
color
:
$dark-grey
;
font-weight
:
$light
;
}
.downloadLink
{
color
:
$blue
;
cursor
:
pointer
;
}
.downloadWrapper
{
display
:
inline-block
;
margin-left
:
40px
;
min-width
:
600px
;
position
:
relative
;
}
.closeButton
{
position
:
absolute
;
right
:
0
;
top
:
0
;
}
src/ensembl/src/content/app/browser/drawer/drawer-views/transcript-summary/TranscriptSummary.tsx
View file @
ff75bed5
...
...
@@ -14,70 +14,323 @@
* limitations under the License.
*/
import
React
from
'
react
'
;
import
get
from
'
lodash/get
'
;
import
find
from
'
lodash/find
'
;
import
React
,
{
useState
}
from
'
react
'
;
import
{
useSelector
}
from
'
react-redux
'
;
import
{
gql
,
useQuery
}
from
'
@apollo/client
'
;
import
{
getDisplayStableId
}
from
'
src/shared/state/ens-object/ensObjectHelpers
'
;
import
*
as
urlFor
from
'
src/shared/helpers/urlHelper
'
;
import
{
getFormattedLocation
}
from
'
src/shared/helpers/formatters/regionFormatter
'
;
import
{
getStrandDisplayName
}
from
'
src/shared/helpers/formatters/strandFormatter
'
;
import
{
getDisplayStableId
,
buildFocusIdForUrl
}
from
'
src/shared/state/ens-object/ensObjectHelpers
'
;
import
{
getBrowserActiveEnsObject
}
from
'
src/content/app/browser/browserSelectors
'
;
import
{
getCommaSeparatedNumber
}
from
'
src/shared/helpers/formatters/numberFormatter
'
;
// TODO: check if this can be moved to a common place
import
{
getNumberOfCodingExons
,
getSplicedRNALength
}
from
'
src/content/app/entity-viewer/shared/helpers/entity-helpers
'
;
import
{
InstantDownloadTranscript
}
from
'
src/shared/components/instant-download
'
;
import
ViewInApp
from
'
src/shared/components/view-in-app/ViewInApp
'
;
import
ExternalReference
from
'
src/shared/components/external-reference/ExternalReference
'
;
import
CloseButton
from
'
src/shared/components/close-button/CloseButton
'
;
import
{
EnsObjectGene
}
from
'
src/shared/state/ens-object/ensObjectTypes
'
;
import
{
Transcript
as
TranscriptFromGraphql
}
from
'
src/shared/types/thoas/transcript
'
;
import
{
Gene
as
GeneFromGraphql
}
from
'
src/shared/types/thoas/gene
'
;
import
{
ProductGeneratingContext
}
from
'
src/shared/types/thoas/productGeneratingContext
'
;
import
styles
from
'
src/content/app/browser/drawer/Drawer
.scss
'
;
import
styles
from
'
./TranscriptSummary
.scss
'
;
// TODO: Once we start supporting multiple transcripts, we need to either remove this constant or move it to trackConfig
const
TRANSCRIPT_GENE_NAME
=
'
track:gene-feat-1
'
;
type
Transcript
=
Required
<
Pick
<
TranscriptFromGraphql
,
|
'
stable_id
'
|
'
unversioned_stable_id
'
|
'
symbol
'
|
'
so_term
'
|
'
external_references
'
|
'
slice
'
|
'
spliced_exons
'
|
'
product_generating_contexts
'
>
>
;
const
TranscriptSummary
=
()
=>
{
const
ensObject
=
useSelector
(
getBrowserActiveEnsObject
)
as
EnsObjectGene
;
type
Gene
=
Required
<
Pick
<
GeneFromGraphql
,
'
stable_id
'
|
'
unversioned_stable_id
'
|
'
symbol
'
|
'
name
'
>
>
;
if
(
!
ensObject
.
track
)
{
return
null
;
const
GENE_AND_TRANSCRIPT_QUERY
=
gql
`
query Gene($genomeId: String!, $geneId: String!, $transcriptId: String!) {
gene(byId: { genome_id: $genomeId, stable_id: $geneId }) {
name
stable_id
unversioned_stable_id
symbol
}
transcript(byId: { genome_id: $genomeId, stable_id: $transcriptId }) {
stable_id
unversioned_stable_id
so_term
symbol
external_references {
accession_id
url
source {
id
}
}
spliced_exons {
relative_location {
start
end
}
exon {
stable_id
slice {
location {
length
}
}