Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
ensembl-web
ensembl-client
Commits
7a0bc167
Unverified
Commit
7a0bc167
authored
Apr 02, 2021
by
Andrey Azov
Committed by
GitHub
Apr 02, 2021
Browse files
Update help (#478)
parent
5fb91328
Pipeline
#143807
passed with stages
in 7 minutes and 16 seconds
Changes
22
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
778 additions
and
231 deletions
+778
-231
src/ensembl/src/content/app/App.tsx
src/ensembl/src/content/app/App.tsx
+2
-0
src/ensembl/src/content/app/about/About.scss
src/ensembl/src/content/app/about/About.scss
+43
-0
src/ensembl/src/content/app/about/About.tsx
src/ensembl/src/content/app/about/About.tsx
+77
-0
src/ensembl/src/content/app/about/components/about-menu/AboutMenu.scss
...rc/content/app/about/components/about-menu/AboutMenu.scss
+14
-0
src/ensembl/src/content/app/about/components/about-menu/AboutMenu.tsx
...src/content/app/about/components/about-menu/AboutMenu.tsx
+85
-0
src/ensembl/src/header/Header.scss
src/ensembl/src/header/Header.scss
+11
-2
src/ensembl/src/header/Header.tsx
src/ensembl/src/header/Header.tsx
+16
-3
src/ensembl/src/shared/components/help-article/HelpArticle.scss
...sembl/src/shared/components/help-article/HelpArticle.scss
+41
-0
src/ensembl/src/shared/components/help-article/TextArticle.tsx
...nsembl/src/shared/components/help-article/TextArticle.tsx
+73
-0
src/ensembl/src/shared/components/help-article/_helpArticleConstants.scss
...shared/components/help-article/_helpArticleConstants.scss
+4
-0
src/ensembl/src/shared/components/help-article/external-link.svg
...embl/src/shared/components/help-article/external-link.svg
+9
-0
src/ensembl/src/shared/components/help-article/index.tsx
src/ensembl/src/shared/components/help-article/index.tsx
+17
-0
src/ensembl/src/shared/components/help-popup/HelpPopupBody.scss
...sembl/src/shared/components/help-popup/HelpPopupBody.scss
+35
-0
src/ensembl/src/shared/components/help-popup/HelpPopupBody.tsx
...nsembl/src/shared/components/help-popup/HelpPopupBody.tsx
+144
-103
src/ensembl/src/shared/components/help-popup/HelpPopupButton.tsx
...embl/src/shared/components/help-popup/HelpPopupButton.tsx
+3
-11
src/ensembl/src/shared/components/help-popup/helpPopupHistory.test.ts
...src/shared/components/help-popup/helpPopupHistory.test.ts
+66
-0
src/ensembl/src/shared/components/help-popup/helpPopupHistory.ts
...embl/src/shared/components/help-popup/helpPopupHistory.ts
+65
-0
src/ensembl/src/shared/components/help-popup/types.ts
src/ensembl/src/shared/components/help-popup/types.ts
+21
-15
src/ensembl/src/shared/components/help-popup/useHelpArticle.ts
...nsembl/src/shared/components/help-popup/useHelpArticle.ts
+10
-97
src/ensembl/src/shared/types/help-and-docs/article.ts
src/ensembl/src/shared/types/help-and-docs/article.ts
+42
-0
No files found.
src/ensembl/src/content/app/App.tsx
View file @
7a0bc167
...
...
@@ -33,6 +33,7 @@ const SpeciesPage = lazy(() => import('./species/SpeciesPage'));
const
CustomDownload
=
lazy
(()
=>
import
(
'
./custom-download/CustomDownload
'
));
const
Browser
=
lazy
(()
=>
import
(
'
./browser/Browser
'
));
const
EntityViewer
=
lazy
(()
=>
import
(
'
./entity-viewer/EntityViewer
'
));
const
About
=
lazy
(()
=>
import
(
'
./about/About
'
));
type
AppProps
=
{
changeCurrentApp
:
(
name
:
string
)
=>
void
;
...
...
@@ -67,6 +68,7 @@ const App = (props: AppProps) => {
component
=
{
EntityViewer
}
/>
<
Route
path
=
{
`/genome-browser/:genomeId?`
}
component
=
{
Browser
}
/>
<
Route
path
=
{
`/about`
}
component
=
{
About
}
/>
<
Route
>
<
Redirect
to
=
{
{
...
location
,
state
:
{
is404
:
true
}
}
}
/>
</
Route
>
...
...
src/ensembl/src/content/app/about/About.scss
0 → 100644
View file @
7a0bc167
@import
'src/styles/common'
;
@import
'src/shared/components/help-article/helpArticleConstants'
;
$article-right-padding
:
1
.5rem
;
.appBar
{
display
:
flex
;
align-items
:
center
;
height
:
80px
;
padding
:
0
44px
;
}
.topMenuBar
{
display
:
flex
;
align-items
:
center
;
height
:
40px
;
padding
:
0
44px
;
background
:
$light-grey
;
box-shadow
:
0
2px
3px
$grey
;
}
.main
{
height
:
100%
;
display
:
grid
;
grid-template-columns
:
[
article
]
calc
(
440px
+
#{
$article-right-padding
}
)
[
aside
]
minmax
(
200px
,
300px
);
grid-column-gap
:
10rem
;
padding-left
:
80px
;
padding-top
:
44px
;
article
{
grid-column
:
article
;
}
aside
{
display
:
flex
;
flex-direction
:
column
;
grid-column
:
aside
;
}
.asideTitle
{
margin-bottom
:
$aside-title-margin-bottom
;
}
}
src/ensembl/src/content/app/about/About.tsx
0 → 100644
View file @
7a0bc167
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import
React
,
{
ReactNode
}
from
'
react
'
;
import
{
useLocation
}
from
'
react-router
'
;
import
useApiService
from
'
src/shared/hooks/useApiService
'
;
import
{
TextArticle
}
from
'
src/shared/components/help-article
'
;
import
{
TopMenu
,
SideMenu
}
from
'
src/content/app/about/components/about-menu/AboutMenu
'
;
import
{
Menu
as
MenuType
}
from
'
src/shared/types/help-and-docs/menu
'
;
import
{
TextArticle
as
TextArticleType
}
from
'
src/shared/types/help-and-docs/article
'
;
import
styles
from
'
./About.scss
'
;
const
About
=
()
=>
{
const
location
=
useLocation
();
const
{
data
:
menu
}
=
useApiService
<
MenuType
>
({
endpoint
:
`/api/docs/menus?name=about`
});
const
{
data
:
article
}
=
useApiService
<
TextArticleType
>
({
endpoint
:
`/api/docs/article?url=
${
encodeURIComponent
(
location
.
pathname
)}
`
});
return
(
<>
<
div
>
<
AppBar
/>
<
TopMenuBar
>
{
menu
&&
<
TopMenu
menu
=
{
menu
}
currentUrl
=
{
location
.
pathname
}
/>
}
</
TopMenuBar
>
</
div
>
<
Main
>
{
article
&&
<
TextArticle
article
=
{
article
}
/>
}
<
aside
>
{
menu
&&
(
<>
<
div
className
=
{
styles
.
asideTitle
}
>
More about...
</
div
>
<
SideMenu
menu
=
{
menu
}
currentUrl
=
{
location
.
pathname
}
/>
</>
)
}
</
aside
>
</
Main
>
</>
);
};
const
AppBar
=
()
=>
{
return
<
div
className
=
{
styles
.
appBar
}
>
About Ensembl
</
div
>;
};
const
TopMenuBar
=
(
props
:
{
children
:
ReactNode
})
=>
{
return
<
div
className
=
{
styles
.
topMenuBar
}
>
{
props
.
children
}
</
div
>;
};
const
Main
=
(
props
:
{
children
:
ReactNode
})
=>
{
return
<
main
className
=
{
styles
.
main
}
>
{
props
.
children
}
</
main
>;
};
export
default
About
;
src/ensembl/src/content/app/about/components/about-menu/AboutMenu.scss
0 → 100644
View file @
7a0bc167
@import
'src/styles/common'
;
.topMenuLink
+
.topMenuLink
{
margin-left
:
2rem
;
}
.sideMenuLink
{
display
:
inline-block
;
padding
:
0
.3rem
;
}
.activeLink
{
color
:
$black
;
}
src/ensembl/src/content/app/about/components/about-menu/AboutMenu.tsx
0 → 100644
View file @
7a0bc167
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import
React
from
'
react
'
;
import
{
Link
}
from
'
react-router-dom
'
;
import
classNames
from
'
classnames
'
;
import
{
Menu
as
MenuType
}
from
'
src/shared/types/help-and-docs/menu
'
;
import
{
MenuItem
}
from
'
src/shared/types/help-and-docs/menu
'
;
import
styles
from
'
./AboutMenu.scss
'
;
type
Props
=
{
menu
:
MenuType
;
currentUrl
:
string
;
};
export
const
TopMenu
=
(
props
:
Props
)
=>
{
return
(
<>
{
props
.
menu
.
items
.
map
((
item
,
index
)
=>
{
const
className
=
classNames
(
styles
.
topMenuLink
,
{
[
styles
.
activeLink
]:
hasItemWithUrl
(
item
,
props
.
currentUrl
)
});
return
(
<
Link
className
=
{
className
}
to
=
{
item
.
url
as
string
}
key
=
{
index
}
>
{
item
.
name
}
</
Link
>
);
})
}
</>
);
};
export
const
SideMenu
=
(
props
:
Props
)
=>
{
const
{
menu
,
currentUrl
}
=
props
;
const
menuItem
=
menu
.
items
.
find
(
(
menuItem
)
=>
menuItem
.
type
===
'
collection
'
&&
menuItem
.
items
.
find
((
item
)
=>
item
.
url
===
currentUrl
)
);
if
(
!
menuItem
||
menuItem
.
type
!==
'
collection
'
)
{
// this shouldn't happen
return
null
;
}
return
(
<>
{
menuItem
.
items
.
map
((
item
,
index
)
=>
{
const
linkClasses
=
classNames
(
styles
.
sideMenuLink
,
{
[
styles
.
activeLink
]:
item
.
url
===
currentUrl
});
return
(
<
Link
className
=
{
linkClasses
}
to
=
{
item
.
url
as
string
}
key
=
{
index
}
>
{
item
.
name
}
</
Link
>
);
})
}
</>
);
};
const
hasItemWithUrl
=
(
menuItem
:
MenuItem
,
url
:
string
):
boolean
=>
{
if
(
menuItem
.
url
===
url
)
{
return
true
;
}
else
if
(
menuItem
.
type
===
'
collection
'
&&
menuItem
.
items
.
length
)
{
return
menuItem
.
items
.
some
((
item
)
=>
hasItemWithUrl
(
item
,
url
));
}
return
false
;
};
src/ensembl/src/header/Header.scss
View file @
7a0bc167
...
...
@@ -66,11 +66,20 @@
align-items
:
baseline
;
margin-top
:
4px
;
font-size
:
12px
;
color
:
$
medium-dark-grey
;
color
:
$
light-blue
;
}
.logotypeAbout
{
height
:
10px
;
fill
:
$
medium-dark-grey
;
fill
:
$
light-blue
;
margin-left
:
0
.5rem
;
}
// For disabling temporarily the about Ensembl link in production
.aboutEnsemblDisabled
{
color
:
$medium-dark-grey
;
.logotypeAbout
{
fill
:
$medium-dark-grey
;
}
}
src/ensembl/src/header/Header.tsx
View file @
7a0bc167
...
...
@@ -17,6 +17,8 @@
import
React
from
'
react
'
;
import
{
Link
}
from
'
react-router-dom
'
;
import
{
isEnvironment
,
Environment
}
from
'
src/shared/helpers/environment
'
;
import
LaunchbarContainer
from
'
./launchbar/LaunchbarContainer
'
;
import
Account
from
'
./account/Account
'
;
...
...
@@ -59,12 +61,23 @@ export const Topbar = () => (
</
div
>
</
div
>
</
div
>
<
div
className
=
{
styles
.
aboutEnsembl
}
>
<
AboutEnsembl
/>
</
div
>
);
// Temporarily disable the link to About Ensembl in production
const
AboutEnsembl
=
()
=>
isEnvironment
([
Environment
.
DEVELOPMENT
,
Environment
.
INTERNAL
])
?
(
<
Link
to
=
"/about"
className
=
{
styles
.
aboutEnsembl
}
>
About
<
Logotype
className
=
{
styles
.
logotypeAbout
}
/>
</
Link
>
)
:
(
<
div
className
=
{
styles
.
aboutEnsemblDisabled
}
>
About
<
Logotype
className
=
{
styles
.
logotypeAbout
}
/>
</
div
>
</
div
>
);
);
export
const
Header
=
()
=>
(
<
header
>
...
...
src/ensembl/src/shared/components/help-article/HelpArticle.scss
0 → 100644
View file @
7a0bc167
@import
'src/styles/common'
;
@import
'helpArticleConstants'
;
.textArticle
{
h1
{
font-size
:
15px
;
line-height
:
18px
;
font-weight
:
$normal
;
margin
:
0
0
#{
$heading-margin-bottom
}
-
#{
$heading-outdent
}
;
}
h2
{
font-size
:
13px
;
margin-top
:
calc
(
2
*
#{
$line-height
}
);
margin-bottom
:
$line-height
;
}
p
{
line-height
:
$line-height
;
margin
:
$line-height
0
;
}
img
{
max-width
:
100%
;
}
// Notice that the external-link svg has the same shape as in the static/img/shared folder
// But the version copied here has the fill color set inline, because it is being accessed as an external image via url
a
[
href
^=
http
]
{
&
::before
{
content
:
url('./external-link.svg')
;
display
:
inline-block
;
margin
:
0
0
.125rem
;
position
:
relative
;
height
:
10px
;
width
:
10px
;
}
}
}
src/ensembl/src/shared/components/help-article/TextArticle.tsx
0 → 100644
View file @
7a0bc167
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import
React
,
{
useRef
,
useEffect
,
RefObject
}
from
'
react
'
;
import
{
useDispatch
}
from
'
react-redux
'
;
import
{
push
}
from
'
connected-react-router
'
;
import
{
TextArticle
as
TextArticleType
}
from
'
src/shared/types/help-and-docs/article
'
;
import
styles
from
'
./HelpArticle.scss
'
;
type
Props
=
{
article
:
TextArticleType
;
className
?:
string
;
};
const
TextArticle
=
(
props
:
Props
)
=>
{
const
articleRef
=
useRef
<
HTMLElement
|
null
>
(
null
);
useRoutingRules
(
articleRef
);
return
(
<
article
ref
=
{
articleRef
}
className
=
{
styles
.
textArticle
}
dangerouslySetInnerHTML
=
{
{
__html
:
props
.
article
.
body
}
}
/>
);
};
const
useRoutingRules
=
<
T
extends
HTMLElement
>
(ref: RefObject
<
T
>
) =>
{
const
dispatch
=
useDispatch
();
const
onClick
=
(
event
:
MouseEvent
)
=>
{
event
.
preventDefault
();
const
target
=
event
.
target
as
HTMLElement
;
if
(
!
target
?.
matches
(
'
a
'
))
{
return
;
}
const
href
=
target
.
getAttribute
(
'
href
'
)
as
string
;
if
(
href
.
startsWith
(
'
/
'
))
{
// This is a link to another page within the site;
// Use React Router to navigate;
dispatch
(
push
(
href
));
}
else
{
// A href containing an absolute urls, with a protocol and a hostname
// is treated as a link to an external resource; open it in a new tab
window
.
open
(
href
);
}
};
useEffect
(()
=>
{
ref
?.
current
?.
addEventListener
(
'
click
'
,
onClick
);
return
()
=>
ref
?.
current
?.
removeEventListener
(
'
click
'
,
onClick
);
});
}
;
export default TextArticle;
src/ensembl/src/shared/components/help-article/_helpArticleConstants.scss
0 → 100644
View file @
7a0bc167
$heading-outdent
:
16px
;
$heading-margin-bottom
:
27px
;
$aside-title-margin-bottom
:
$heading-margin-bottom
;
$line-height
:
17px
;
src/ensembl/src/shared/components/help-article/external-link.svg
0 → 100644
View file @
7a0bc167
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version=
"1.1"
id=
"user"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
x=
"0px"
y=
"0px"
viewBox=
"0 0 32 32"
style=
"enable-background:new 0 0 32 32;"
xml:space=
"preserve"
>
<path
fill=
"#ff9900"
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M22,5.2c0,0-0.1,0.1-0.1,0.1l-8.5,8.7c-1,1-1,2.5,0,3.5l1.2,1.2c1,1,2.5,1,3.5,0l8.5-8.7c0,0,0.1-0.1,0.1-0.1
l2.6,2.7c1,1,1.7,0.6,1.7-0.7V1.8C31,1.4,30.6,1,30.2,1h-9.8c-1.4,0-1.7,0.8-0.7,1.8C19.7,2.8,22,5.2,22,5.2z M6,1C3.2,1,1,3.2,1,6
v20c0,2.8,2.2,5,5,5h20c2.8,0,5-2.2,5-5V13.1v7.1L26,16v7.5c0,1.4-1.1,2.5-2.5,2.5h-15C7.1,26,6,24.9,6,23.5v-15C6,7.1,7.1,6,8.5,6
H16l-4.2-5h7.1C18.9,1,6,1,6,1z"
/>
</svg>
src/ensembl/src/shared/components/help-article/index.tsx
0 → 100644
View file @
7a0bc167
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export
{
default
as
TextArticle
}
from
'
./TextArticle
'
;
src/ensembl/src/shared/components/help-popup/HelpPopupBody.scss
View file @
7a0bc167
...
...
@@ -61,6 +61,15 @@ $article-right-padding: 1.5rem; // area over which Macs (which hide their scroll
}
}
.videoLoadingIndicator
{
position
:
absolute
;
height
:
100%
;
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
.aside
{
grid-column
:
aside
;
padding-left
:
$aside-left-padding
;
...
...
@@ -111,3 +120,29 @@ $article-right-padding: 1.5rem; // area over which Macs (which hide their scroll
fill
:
white
;
}
}
.historyButtons
{
position
:
absolute
;
top
:
16px
;
line-height
:
0
;
right
:
70px
;
}
.historyButton
{
width
:
18px
;
height
:
18px
;
border-radius
:
100%
;
&
:first-child
{
margin-right
:
1
.4rem
;
}
&
Active
{
fill
:
$blue
;
cursor
:
pointer
;
}
&
Inactive
{
fill
:
$grey
;
}
}
src/ensembl/src/shared/components/help-popup/HelpPopupBody.tsx
View file @
7a0bc167
...
...
@@ -14,91 +14,154 @@
* limitations under the License.
*/
import
React
,
{
useState
,
useRef
,
ReactNode
}
from
'
react
'
;
import
React
,
{
useState
,
useEffect
,
useRef
,
ReactNode
,
MutableRefObject
}
from
'
react
'
;
import
classNames
from
'
classnames
'
;
import
useHelpArticle
,
{
emptyRelatedItems
,
CurrentArticle
,
CurrentVideo
,
CurrentItem
,
RelatedItems
as
RelatedItemsType
,
ArticleReference
,
VideoReference
}
from
'
./useHelpArticle
'
;
import
useResizeObserver
from
'
src/shared/hooks/useResizeObserver.ts
'
;
import
HelpPopupHistory
from
'
./helpPopupHistory
'
;
import
useHelpArticle
,
{
Article
as
ArticleType
}
from
'
./useHelpArticle
'
;
import
useResizeObserver
from
'
src/shared/hooks/useResizeObserver
'
;
import
{
CircleLoader
}
from
'
src/shared/components/loader/Loader
'
;
import
{
ReactComponent
as
VideoIcon
}
from
'
static/img/shared/video.svg
'
;
import
{
ReactComponent
as
BackIcon
}
from
'
static/img/browser/navigate-left.svg
'
;
import
{
ReactComponent
as
ForwardIcon
}
from
'
static/img/browser/navigate-right.svg
'
;
import
{
LoadingState
}
from
'
src/shared/types/loading-state
'
;
import
{
RelatedArticle
,
HelpVideo
,
SlugReferenc
e
,
Path
Reference
TextArticle
,
VideoArticl
e
,
Slug
Reference
}
from
'
./types
'
;
import
styles
from
'
./HelpPopupBody.scss
'
;
type
Props
=
SlugReference
|
PathReference
;
type
Props
=
SlugReference
;
const
HelpPopupBody
=
(
props
:
Props
)
=>
{
const
[
currentReference
,
setCurrentReference
]
=
useState
<
ArticleReference
|
VideoReference
>
(
createArticleReference
(
props
));
const
{
currentHelpItem
,
relatedHelpItems
}
=
useHelpArticle
(
currentReference
const
[
currentReference
,
setCurrentReference
]
=
useState
<
SlugReference
>
(
props
);
const
{
article
,
loadingState
}
=
useHelpArticle
(
currentReference
);
const
historyRef
=
useRef
<
HelpPopupHistory
|
null
>
(
null
);
useEffect
(()
=>
{
historyRef
.
current
=
new
HelpPopupHistory
(
currentReference
);
},
[]);
const
onRelatedItemClick
=
(
reference
:
ArticleReference
|
VideoReference
)
=>
{
const
onRelatedItemClick
=
(
reference
:
SlugReference
)
=>
{
historyRef
.
current
?.
add
(
reference
);
setCurrentReference
(
reference
);
};
if
(
currentHelpItem
?.
type
===
'
article
'
)
{
const
onHistoryBack
=
()
=>
{
const
prevReference
=
historyRef
.
current
?.
getPrevious
();
if
(
prevReference
)
{
setCurrentReference
(
prevReference
);
}
};
const
onHistoryForward
=
()
=>
{
const
nextReference
=
historyRef
.
current
?.
getNext
();
if
(
nextReference
)
{
setCurrentReference
(
nextReference
);
}
};