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
100d5a25
Unverified
Commit
100d5a25
authored
May 06, 2022
by
Andrey Azov
Committed by
GitHub
May 06, 2022
Browse files
Add a page for unviewed BLAST submissions (#740)
parent
bbd47e9f
Pipeline
#276147
passed with stages
in 5 minutes and 28 seconds
Changes
11
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
193 additions
and
53 deletions
+193
-53
src/content/app/tools/blast/BlastPage.tsx
src/content/app/tools/blast/BlastPage.tsx
+11
-2
src/content/app/tools/blast/components/blast-app-bar/BlastAppBar.test.tsx
...tools/blast/components/blast-app-bar/BlastAppBar.test.tsx
+3
-3
src/content/app/tools/blast/components/blast-app-bar/BlastAppBar.tsx
.../app/tools/blast/components/blast-app-bar/BlastAppBar.tsx
+27
-3
src/content/app/tools/blast/components/blast-job-submit/BlastJobSubmit.tsx
...ools/blast/components/blast-job-submit/BlastJobSubmit.tsx
+14
-37
src/content/app/tools/blast/components/blast-views-navigation/BlastViewsNavigation.scss
...mponents/blast-views-navigation/BlastViewsNavigation.scss
+34
-0
src/content/app/tools/blast/components/blast-views-navigation/BlastViewsNavigation.tsx
...omponents/blast-views-navigation/BlastViewsNavigation.tsx
+48
-0
src/content/app/tools/blast/state/blast-api/blastApiSlice.ts
src/content/app/tools/blast/state/blast-api/blastApiSlice.ts
+1
-1
src/content/app/tools/blast/views/blast-form/BlastForm.tsx
src/content/app/tools/blast/views/blast-form/BlastForm.tsx
+2
-2
src/content/app/tools/blast/views/blast-submissions/BlastSubmissions.tsx
.../tools/blast/views/blast-submissions/BlastSubmissions.tsx
+8
-5
src/content/app/tools/blast/views/blast-unviewed-submissions/BlastUnviewedSubmissions.tsx
...s/blast-unviewed-submissions/BlastUnviewedSubmissions.tsx
+39
-0
src/shared/helpers/urlHelper.ts
src/shared/helpers/urlHelper.ts
+6
-0
No files found.
src/content/app/tools/blast/BlastPage.tsx
View file @
100d5a25
...
...
@@ -22,7 +22,12 @@ import loadable from '@loadable/component';
import
useHasMounted
from
'
src/shared/hooks/useHasMounted
'
;
const
BlastForm
=
loadable
(()
=>
import
(
'
./views/blast-form/BlastForm
'
));
const
BlastJobs
=
loadable
(()
=>
import
(
'
./views/blast-jobs/BlastJobs
'
));
const
BlastUnviewedSubmissions
=
loadable
(
()
=>
import
(
'
./views/blast-unviewed-submissions/BlastUnviewedSubmissions
'
)
);
const
BlastJobs
=
loadable
(
()
=>
import
(
'
./views/blast-submissions/BlastSubmissions
'
)
);
const
pageDescription
=
`
BLAST stands for Basic Local Alignment Search Tool.
...
...
@@ -41,7 +46,11 @@ const BrowserPage = () => {
{
hasMounted
&&
(
<
Routes
>
<
Route
index
element
=
{
<
BlastForm
/>
}
/>
<
Route
path
=
"jobs"
element
=
{
<
BlastJobs
/>
}
/>
<
Route
path
=
"unviewed-submissions"
element
=
{
<
BlastUnviewedSubmissions
/>
}
/>
<
Route
path
=
"submissions"
element
=
{
<
BlastJobs
/>
}
/>
</
Routes
>
)
}
</>
...
...
src/content/app/tools/
shared
/components/
tools
-app-bar/
Tools
AppBar.test.tsx
→
src/content/app/tools/
blast
/components/
blast
-app-bar/
Blast
AppBar.test.tsx
View file @
100d5a25
...
...
@@ -29,7 +29,7 @@ import speciesSelectorReducer, {
SpeciesSelectorState
}
from
'
src/content/app/species-selector/state/speciesSelectorSlice
'
;
import
Tools
AppBar
from
'
./
Tools
AppBar
'
;
import
Blast
AppBar
from
'
./
Blast
AppBar
'
;
jest
.
mock
(
'
src/shared/components/communication-framework/ConversationIcon
'
,
...
...
@@ -70,7 +70,7 @@ const renderComponent = () => {
const
renderResult
=
render
(
<
Provider
store
=
{
store
}
>
<
MemoryRouter
>
<
Tools
AppBar
/>
<
Blast
AppBar
view
=
"blast-form"
/>
</
MemoryRouter
>
</
Provider
>
);
...
...
@@ -81,7 +81,7 @@ const renderComponent = () => {
};
};
describe
(
'
Tools
AppBar
'
,
()
=>
{
describe
(
'
Blast
AppBar
'
,
()
=>
{
describe
(
'
Species Lozenge click
'
,
()
=>
{
it
(
'
updates the selectedSpecies state
'
,
async
()
=>
{
const
{
container
,
store
}
=
renderComponent
();
...
...
src/content/app/tools/
shared
/components/
tools
-app-bar/
Tools
AppBar.tsx
→
src/content/app/tools/
blast
/components/
blast
-app-bar/
Blast
AppBar.tsx
View file @
100d5a25
...
...
@@ -17,6 +17,7 @@
import
React
,
{
useMemo
}
from
'
react
'
;
import
{
useDispatch
,
useSelector
}
from
'
react-redux
'
;
import
{
Link
}
from
'
react-router-dom
'
;
import
noop
from
'
lodash/noop
'
;
import
*
as
urlFor
from
'
src/shared/helpers/urlHelper
'
;
import
{
AppName
}
from
'
src/global/globalConfig
'
;
...
...
@@ -32,7 +33,18 @@ import SpeciesTabsWrapper from 'src/shared/components/species-tabs-wrapper/Speci
import
type
{
CommittedItem
}
from
'
src/content/app/species-selector/types/species-search
'
;
const
ToolsAppBar
=
()
=>
{
type
BlastView
=
|
'
blast-form
'
|
'
unviewed-submissions
'
|
'
submissions-list
'
|
'
submission-results
'
;
type
Props
=
{
view
:
BlastView
;
};
const
BlastAppBar
=
(
props
:
Props
)
=>
{
const
{
view
}
=
props
;
const
speciesList
=
useSelector
(
getEnabledCommittedSpecies
);
const
speciesListIds
=
useSelector
(
getSelectedSpeciesIds
);
const
dispatch
=
useDispatch
();
...
...
@@ -50,13 +62,25 @@ const ToolsAppBar = () => {
}
};
const
s
pecies
Tabs
=
speciesList
.
map
((
species
,
index
)
=>
(
const
enabledS
pecies
=
speciesList
.
map
((
species
,
index
)
=>
(
<
SelectedSpecies
key
=
{
index
}
species
=
{
species
}
onClick
=
{
()
=>
speciesLozengeClick
(
species
)
}
/>
));
const
disabledSpecies
=
speciesList
.
map
((
species
,
index
)
=>
(
<
SelectedSpecies
key
=
{
index
}
isActive
=
{
true
}
species
=
{
{
...
species
,
isEnabled
:
false
}
}
onClick
=
{
noop
}
/>
));
const
speciesTabs
=
view
===
'
blast-form
'
?
enabledSpecies
:
disabledSpecies
;
const
speciesSelectorLink
=
useMemo
(()
=>
{
return
<
Link
to
=
{
urlFor
.
speciesSelector
()
}
>
Change
</
Link
>;
},
[]);
...
...
@@ -68,4 +92,4 @@ const ToolsAppBar = () => {
return
<
AppBar
appName
=
{
AppName
.
TOOLS
}
mainContent
=
{
wrappedSpecies
}
/>;
};
export
default
Tools
AppBar
;
export
default
Blast
AppBar
;
src/content/app/tools/blast/components/blast-job-submit/BlastJobSubmit.tsx
View file @
100d5a25
...
...
@@ -15,13 +15,13 @@
*/
import
React
from
'
react
'
;
import
{
useNavigate
}
from
'
react-router-dom
'
;
import
{
useAppDispatch
,
useAppSelector
}
from
'
src/store
'
;
import
*
as
urlFor
from
'
src/shared/helpers/urlHelper
'
;
import
{
submitBlast
}
from
'
src/content/app/tools/blast/state/blast-api/blastApiSlice
'
;
import
LoadingButton
from
'
src/shared/components/loading-button/LoadingButton
'
;
import
{
useAppSelector
}
from
'
src/store
'
;
import
{
useSubmitBlastMutation
}
from
'
src/content/app/tools/blast/state/blast-api/blastApiSlice
'
;
import
useBlastInputSequences
from
'
src/content/app/tools/blast/components/blast-input-sequences/useBlastInputSequences
'
;
import
{
isBlastFormValid
}
from
'
src/content/app/tools/blast/utils/blastFormValidator
'
;
...
...
@@ -30,6 +30,8 @@ import { getSelectedSpeciesIds } from 'src/content/app/tools/blast/state/blast-f
import
{
toFasta
}
from
'
src/shared/helpers/formatters/fastaFormatter
'
;
import
{
PrimaryButton
}
from
'
src/shared/components/button/Button
'
;
import
type
{
Species
,
BlastFormState
...
...
@@ -38,7 +40,6 @@ import type {
BlastParameterName
,
SequenceType
}
from
'
src/content/app/tools/blast/types/blastSettings
'
;
import
type
{
BlastSubmission
}
from
'
src/content/app/tools/blast/state/blast-results/blastResultsSlice
'
;
export
type
PayloadParams
=
{
species
:
Species
[];
...
...
@@ -49,51 +50,27 @@ export type PayloadParams = {
};
};
type
BlastSubmissionResponse
=
{
submissionId
:
string
;
submission
:
BlastSubmission
;
};
const
BlastJobSubmit
=
()
=>
{
const
{
sequences
}
=
useBlastInputSequences
();
const
selectedSpeciesIds
=
useAppSelector
(
getSelectedSpeciesIds
);
const
dispatch
=
useAppDispatch
();
const
[
submitBlast
]
=
useSubmitBlastMutation
();
const
navigate
=
useNavigate
();
const
isDisabled
=
!
isBlastFormValid
(
selectedSpeciesIds
,
sequences
);
const
blastFormData
=
useAppSelector
(
getBlastFormData
);
const
onBlastSubmit
=
async
()
=>
{
const
onBlastSubmit
=
()
=>
{
const
payload
=
createBlastSubmissionData
(
blastFormData
);
const
submission
=
dispatch
(
submitBlast
.
initiate
(
payload
));
submission
.
then
((
response
)
=>
{
submission
.
reset
();
// prevent indefinite caching of subscription result
if
(
'
data
'
in
response
)
{
onSubmitSuccess
(
response
.
data
);
}
});
};
const
onSubmitSuccess
=
(
response
:
BlastSubmissionResponse
)
=>
{
// TODO: change the temporary implementation of this function with a more permanent one
const
firstJobId
=
response
.
submission
.
results
[
0
].
jobId
;
if
(
!
firstJobId
)
{
return
;
}
const
resultPageUrl
=
`https://wwwdev.ebi.ac.uk/Tools/services/web/toolresult.ebi?jobId=
${
firstJobId
}
`
;
const
resultTab
=
window
.
open
(
resultPageUrl
,
'
_blank
'
);
if
(
resultTab
!==
null
)
{
resultTab
.
focus
();
}
const
submission
=
submitBlast
(
payload
);
submission
.
then
(()
=>
submission
.
reset
());
navigate
(
urlFor
.
blastUnviewedSubmissions
());
};
return
(
<
Loading
Button
onClick
=
{
onBlastSubmit
}
isDisabled
=
{
isDisabled
}
>
<
Primary
Button
onClick
=
{
onBlastSubmit
}
isDisabled
=
{
isDisabled
}
>
Run
</
Loading
Button
>
</
Primary
Button
>
);
};
...
...
src/content/app/tools/blast/components/blast-views-navigation/BlastViewsNavigation.scss
0 → 100644
View file @
100d5a25
.blastViewsNavigation
{
display
:
grid
;
grid-template-columns
:
[
left
]
auto
[
right
]
1fr
;
height
:
74px
;
// this isn't ideal; but 100% won't work because the parent container only has a min-height
align-items
:
center
;
max-width
:
1810px
;
// TODO: this is max width of the two-column blast form; set it to a constant
padding-right
:
20px
;
// same as in the app bar above
}
.title
{
font-size
:
16px
;
// TODO: this is a title repeated in another component; extract as a common variable
font-weight
:
bold
;
margin
:
0
;
}
.wrapperLeft
{
display
:
flex
;
column-gap
:
46px
;
align-items
:
center
;
}
.wrapperRight
{
display
:
flex
;
column-gap
:
12px
;
}
.leftColumn
{
grid-column
:
left
;
}
.rightColumn
{
grid-column
:
right
;
justify-self
:
end
;
}
src/content/app/tools/blast/components/blast-views-navigation/BlastViewsNavigation.tsx
0 → 100644
View file @
100d5a25
/**
* 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
*
as
urlFor
from
'
src/shared/helpers/urlHelper
'
;
import
ButtonLink
from
'
src/shared/components/button-link/ButtonLink
'
;
import
styles
from
'
./BlastViewsNavigation.scss
'
;
const
BlastViewsNavigation
=
()
=>
{
return
(
<
div
className
=
{
styles
.
blastViewsNavigation
}
>
<
div
className
=
{
styles
.
leftColumn
}
>
<
div
className
=
{
styles
.
wrapperLeft
}
>
<
h1
className
=
{
styles
.
title
}
>
Blast
</
h1
>
<
ButtonLink
to
=
{
urlFor
.
blastForm
()
}
end
=
{
true
}
>
New job
</
ButtonLink
>
</
div
>
</
div
>
<
div
className
=
{
styles
.
rightColumn
}
>
<
div
className
=
{
styles
.
wrapperRight
}
>
<
ButtonLink
to
=
{
urlFor
.
blastUnviewedSubmissions
()
}
>
Unviewed jobs
</
ButtonLink
>
<
ButtonLink
to
=
{
urlFor
.
blastSubmissionsList
()
}
>
Jobs list
</
ButtonLink
>
</
div
>
</
div
>
</
div
>
);
};
export
default
BlastViewsNavigation
;
src/content/app/tools/blast/state/blast-api/blastApiSlice.ts
View file @
100d5a25
...
...
@@ -100,5 +100,5 @@ const blastApiSlice = restApiSlice.injectEndpoints({
})
});
export
const
{
useBlastConfigQuery
}
=
blastApiSlice
;
export
const
{
useBlastConfigQuery
,
useSubmitBlastMutation
}
=
blastApiSlice
;
export
const
{
submitBlast
}
=
blastApiSlice
.
endpoints
;
src/content/app/tools/blast/views/blast-form/BlastForm.tsx
View file @
100d5a25
...
...
@@ -22,7 +22,7 @@ import useMediaQuery from 'src/shared/hooks/useMediaQuery';
import
{
getStep
}
from
'
src/content/app/tools/blast/state/blast-form/blastFormSelectors
'
;
import
Tools
AppBar
from
'
src/content/app/tools/
shared
/components/
tools
-app-bar/
Tools
AppBar
'
;
import
Blast
AppBar
from
'
src/content/app/tools/
blast
/components/
blast
-app-bar/
Blast
AppBar
'
;
import
ToolsTopBar
from
'
src/content/app/tools/shared/components/tools-top-bar/ToolsTopBar
'
;
import
BlastInputSequencesHeader
from
'
src/content/app/tools/blast/components/blast-input-sequences/BlastInputSequencesHeader
'
;
...
...
@@ -43,7 +43,7 @@ const BlastForm = () => {
return
(
<
div
className
=
{
styles
.
container
}
>
<
Tools
AppBar
/>
<
Blast
AppBar
view
=
"blast-form"
/>
<
ToolsTopBar
>
<
BlastSettings
config
=
{
config
}
/>
</
ToolsTopBar
>
...
...
src/content/app/tools/blast/views/blast-
jobs/BlastJob
s.tsx
→
src/content/app/tools/blast/views/blast-
submissions/BlastSubmission
s.tsx
View file @
100d5a25
...
...
@@ -16,17 +16,20 @@
import
React
from
'
react
'
;
import
Tools
AppBar
from
'
src/content/app/tools/
shared
/components/
tools
-app-bar/
Tools
AppBar
'
;
import
Blast
AppBar
from
'
src/content/app/tools/
blast
/components/
blast
-app-bar/
Blast
AppBar
'
;
import
ToolsTopBar
from
'
src/content/app/tools/shared/components/tools-top-bar/ToolsTopBar
'
;
import
BlastViewsNavigation
from
'
src/content/app/tools/blast/components/blast-views-navigation/BlastViewsNavigation
'
;
const
Blast
Result
s
=
()
=>
{
const
Blast
Submission
s
=
()
=>
{
return
(
<
div
>
<
ToolsAppBar
/>
<
ToolsTopBar
>
stuff
</
ToolsTopBar
>
<
BlastAppBar
view
=
"submissions-list"
/>
<
ToolsTopBar
>
<
BlastViewsNavigation
/>
</
ToolsTopBar
>
<
div
>
This is Blast results view
</
div
>
</
div
>
);
};
export
default
Blast
Result
s
;
export
default
Blast
Submission
s
;
src/content/app/tools/blast/views/blast-unviewed-submissions/BlastUnviewedSubmissions.tsx
0 → 100644
View file @
100d5a25
/**
* 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
BlastAppBar
from
'
src/content/app/tools/blast/components/blast-app-bar/BlastAppBar
'
;
import
ToolsTopBar
from
'
src/content/app/tools/shared/components/tools-top-bar/ToolsTopBar
'
;
import
BlastViewsNavigation
from
'
src/content/app/tools/blast/components/blast-views-navigation/BlastViewsNavigation
'
;
const
BlastUnviewedSubmission
=
()
=>
{
return
(
<
div
>
<
BlastAppBar
view
=
"unviewed-submissions"
/>
<
ToolsTopBar
>
<
BlastViewsNavigation
/>
</
ToolsTopBar
>
<
Main
/>
</
div
>
);
};
const
Main
=
()
=>
{
return
<
main
>
The submissions list will go here
</
main
>;
};
export
default
BlastUnviewedSubmission
;
src/shared/helpers/urlHelper.ts
View file @
100d5a25
...
...
@@ -94,6 +94,12 @@ export const entityViewer = (params?: EntityViewerUrlParams) => {
return
query
?
`
${
path
}
?
${
query
}
`
:
path
;
};
export
const
blastForm
=
()
=>
'
/blast
'
;
export
const
blastUnviewedSubmissions
=
()
=>
'
/blast/unviewed-submissions
'
;
export
const
blastSubmissionsList
=
()
=>
'
/blast/submissions
'
;
type
RefgetUrlParams
=
{
checksum
:
string
;
start
?:
number
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment