Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
Datahub
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
93
Issues
93
List
Boards
Labels
Service Desk
Milestones
Jira
Jira
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ICAT
Datahub
Commits
208cc9b7
Commit
208cc9b7
authored
Sep 21, 2020
by
Axel Bocciarelli
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix selection and mint pages
parent
5c2d2c5d
Pipeline
#33789
passed with stage
in 2 minutes and 51 seconds
Changes
10
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
183 additions
and
387 deletions
+183
-387
src/App.js
src/App.js
+7
-2
src/actions/selection.js
src/actions/selection.js
+0
-19
src/components/Dataset/DatasetTable.js
src/components/Dataset/DatasetTable.js
+2
-6
src/components/Menu/Menu.js
src/components/Menu/Menu.js
+14
-11
src/components/doi/DOIForm.js
src/components/doi/DOIForm.js
+6
-8
src/constants/actionTypes.js
src/constants/actionTypes.js
+0
-2
src/containers/Selection/MintSelectionPage.js
src/containers/Selection/MintSelectionPage.js
+79
-185
src/containers/Selection/SelectionPage.js
src/containers/Selection/SelectionPage.js
+63
-131
src/reducers/selection.js
src/reducers/selection.js
+10
-22
src/styles/base.css
src/styles/base.css
+2
-1
No files found.
src/App.js
View file @
208cc9b7
...
...
@@ -157,8 +157,13 @@ function App() {
<
/LoadingBoundary
>
<
/Route
>
<
Route
exact
path
=
"
/selection
"
component
=
{
SelectionPage
}
/
>
<
Route
exact
path
=
"
/selection/mint
"
component
=
{
MintSelectionPage
}
/
>
<
Route
exact
path
=
"
/selection
"
>
<
SelectionPage
/>
<
/Route
>
<
Route
exact
path
=
"
/selection/mint
"
>
<
MintSelectionPage
/>
<
/Route
>
{
user
.
isAdministrator
&&
(
<
Route
exact
path
=
"
/manager/stats
"
>
...
...
src/actions/selection.js
View file @
208cc9b7
import
{
ADD_DATASET_BY_ID
,
ADD_INVESTIGATION_BY_ID
,
REMOVE_DATASET_BY_ID
,
REMOVE_INVESTIGATION_BY_ID
,
}
from
'
../constants/actionTypes
'
;
export
function
addInvestigationById
(
investigationId
)
{
return
function
(
dispatch
)
{
dispatch
({
type
:
ADD_INVESTIGATION_BY_ID
,
payload
:
investigationId
,
});
};
}
export
function
removeInvestigationById
(
investigationId
)
{
return
function
(
dispatch
)
{
dispatch
({
type
:
REMOVE_INVESTIGATION_BY_ID
,
payload
:
investigationId
,
});
};
}
export
function
removeDatasetById
(
datasetId
)
{
return
function
(
dispatch
)
{
dispatch
({
...
...
src/components/Dataset/DatasetTable.js
View file @
208cc9b7
...
...
@@ -214,7 +214,7 @@ class DatasetTable extends React.Component {
const
selectRow
=
{
mode
:
'
checkbox
'
,
clickToSelect
:
false
,
selected
:
this
.
props
.
select
ion
.
d
atasetIds
,
selected
:
this
.
props
.
select
edD
atasetIds
,
onSelectAll
:
this
.
handleOnSelectAll
,
onSelect
:
this
.
handleOnSelect
,
classes
:
'
selection-row
'
,
...
...
@@ -233,11 +233,7 @@ class DatasetTable extends React.Component {
<
Glyphicon
glyph
=
{
expanded
?
'
zoom-out
'
:
'
zoom-in
'
}
/
>
),
renderer
:
(
dataset
)
=>
(
<
DatasetWidget
dataset
=
{
dataset
}
sessionId
=
{
this
.
props
.
sessionId
}
selection
=
{
this
.
props
.
selection
}
/
>
<
DatasetWidget
dataset
=
{
dataset
}
sessionId
=
{
this
.
props
.
sessionId
}
/
>
),
};
...
...
src/components/Menu/Menu.js
View file @
208cc9b7
...
...
@@ -72,6 +72,20 @@ function Menu() {
<
NavItem
eventKey
=
"
my
"
>
My
Data
<
/NavItem
>
<
/LinkContainer
>
{
UI
.
menu
.
isMySelectionVisible
&&
selection
.
datasetIds
.
length
>
0
&&
(
<
LinkContainer
to
=
"
/selection
"
>
<
NavItem
eventKey
=
"
selection
"
>
My
Selection
<
span
className
=
"
badge
"
style
=
{{
marginLeft
:
10
,
padding
:
'
2px 7px
'
}}
>
{
selection
.
datasetIds
.
length
}
<
/span
>
<
/NavItem
>
<
/LinkContainer
>
)}
{
UI
.
menu
.
isOpenDataVisible
&&
(
<
LinkContainer
to
=
"
/public
"
>
<
NavItem
eventKey
=
"
open
"
href
=
"
/public
"
>
...
...
@@ -88,17 +102,6 @@ function Menu() {
<
/LinkContainer
>
)}
{
UI
.
menu
.
isMySelectionVisible
&&
selection
.
datasetIds
.
length
>
0
&&
(
<
LinkContainer
to
=
"
/selection
"
>
<
NavItem
eventKey
=
"
selection
"
>
My
Selection
<
span
className
=
"
badge
"
style
=
{{
marginLeft
:
10
}}
>
{
selection
.
datasetIds
.
length
}
<
/span
>
<
/NavItem
>
<
/LinkContainer
>
)}
{
UI
.
sampleTracking
.
enabled
&&
!
isAnonymous
&&
(
<
NavDropdown
eventKey
=
{
3
}
...
...
src/components/doi/DOIForm.js
View file @
208cc9b7
...
...
@@ -35,11 +35,8 @@ class DOIForm extends React.Component {
this
.
authorCount
=
0
;
}
/**
* Add an author to the table
*/
addAuthor
(
investigationUser
)
{
const
authors
=
this
.
state
.
authors
;
const
authors
=
[...
this
.
state
.
authors
]
;
if
(
!
investigationUser
.
fullName
)
{
authors
.
push
({
name
:
this
.
name
.
value
,
...
...
@@ -135,20 +132,22 @@ class DOIForm extends React.Component {
renderButton
()
{
return
(
<
SplitButton
id
=
"
add-author
"
bsStyle
=
"
default
"
title
=
"
Add author
"
style
=
{{
width
:
100
}}
onClick
=
{
this
.
addAuthor
}
>
{
this
.
props
.
investigationUsers
.
map
(
function
(
user
)
{
{
this
.
props
.
investigationUsers
.
map
(
(
user
)
=>
{
const
bsStyleRole
=
user
.
role
===
USER_ROLES
.
PrincipalInvestigator
?
'
primary
'
:
'
default
'
;
return
(
<
MenuItem
style
=
{{
width
:
350
}
}
key
=
{
`
${
user
.
fullName
}
${
user
.
investigationId
}
${
user
.
role
}
`
}
eventKey
=
{
user
}
style
=
{{
width
:
350
}}
onSelect
=
{
this
.
addAuthor
}
>
<
span
style
=
{{
marginLeft
:
10
}}
>
{
user
.
fullName
}
<
/span
>
...
...
@@ -161,7 +160,6 @@ class DOIForm extends React.Component {
<
/MenuItem
>
);
},
this
)}
<
MenuItem
divider
/>
<
/SplitButton
>
);
}
...
...
@@ -201,7 +199,7 @@ class DOIForm extends React.Component {
<
/Panel.Heading
>
<
Panel
.
Body
>
<
Form
inline
>
<
Form
inline
componentClass
=
"
div
"
>
<
FormGroup
controlId
=
"
formInlineName
"
>
<
ControlLabel
>
Name
<
/ControlLabel>{' '
}
<
FormControl
...
...
src/constants/actionTypes.js
View file @
208cc9b7
...
...
@@ -33,8 +33,6 @@ export const SET_LOGBOOK_CONTEXT = 'SET_LOGBOOK_CONTEXT';
/** selection */
export
const
ADD_DATASET_BY_ID
=
'
ADD_DATASET_BY_ID
'
;
export
const
REMOVE_DATASET_BY_ID
=
'
REMOVE_DATASET_BY_ID
'
;
export
const
ADD_INVESTIGATION_BY_ID
=
'
ADD_INVESTIGATION_BY_ID
'
;
export
const
REMOVE_INVESTIGATION_BY_ID
=
'
REMOVE_INVESTIGATION_BY_ID
'
;
/** breadcrumbs */
export
const
SET_BREADCRUMBS
=
'
SET_BREADCRUMBS
'
;
...
...
src/containers/Selection/MintSelectionPage.js
View file @
208cc9b7
import
axios
from
'
axios
'
;
import
{
uniq
}
from
'
lodash-es
'
;
import
PropTypes
from
'
prop-types
'
;
import
React
,
{
Component
}
from
'
react
'
;
import
React
,
{
useEffect
,
useState
}
from
'
react
'
;
import
{
Col
,
Grid
,
Panel
,
Row
}
from
'
react-bootstrap
'
;
import
BootstrapTable2
from
'
react-bootstrap-table-next
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
bindActionCreators
}
from
'
redux
'
;
import
{
doSignIn
}
from
'
../../actions/login
'
;
import
{
addDatasetById
,
removeDatasetById
}
from
'
../../actions/selection
'
;
import
{
useDispatch
,
useSelector
}
from
'
react-redux
'
;
import
{
getDatasetsById
,
getUsersByInvestigationIds
,
}
from
'
../../api/icat-plus/catalogue
'
;
import
DOIForm
from
'
../../components/doi/DOIForm
'
;
import
Loader
from
'
../../components/Loader
'
;
import
{
PERSPECTIVE
}
from
'
../../constants
'
;
class
MintSelectionPage
extends
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
investigationId
:
this
.
props
.
match
.
params
.
id
,
username
:
this
.
props
.
user
.
username
,
sessionId
:
this
.
props
.
user
.
sessionId
,
datasets
:
[],
filtered
:
[],
fetching
:
false
,
fetched
:
false
,
datasetIds
:
this
.
props
.
selection
.
datasetIds
,
investigationUsers
:
[],
};
}
/*
groupBy = function (xs, key) {
return xs.reduce(function (rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
parametersToDatasetObject = function (parametersGroupedByInvestigationId) {
let datasets = {};
for (var datasetId in parametersGroupedByInvestigationId) {
for (var index in parametersGroupedByInvestigationId[datasetId]) {
var param = parametersGroupedByInvestigationId[datasetId][index];
var key = param[5];
var value = param[6];
if (datasets[datasetId] == null) {
datasets[datasetId] = {};
}
datasets[datasetId][key] = value;
datasets[datasetId]["id"] = param[0];
datasets[datasetId]["name"] = param[1];
datasets[datasetId]["startDate"] = param[2];
datasets[datasetId]["endDate"] = param[3];
datasets[datasetId]["investigationName"] = param[4];
datasets[datasetId]["location"] = param[8];
datasets[datasetId]["investigationId"] = param[9];
}
}
var array = [];
for (var ds in datasets) {
array.push(datasets[ds]);
}
return array;
};
*/
onLogbookButtonClicked
()
{
this
.
setState
({
perspective
:
PERSPECTIVE
.
Events
,
});
}
import
{
setBreadCrumbs
}
from
'
../../actions/breadcrumbs
'
;
function
MintSelectionPage
()
{
const
sessionId
=
useSelector
((
state
)
=>
state
.
user
.
sessionId
);
const
datasetIds
=
useSelector
((
state
)
=>
state
.
selection
.
datasetIds
);
const
dispatch
=
useDispatch
();
const
[
state
,
setState
]
=
useState
({
datasets
:
[],
users
:
[],
isFetching
:
false
,
});
const
{
datasets
,
users
,
isFetching
:
fetching
}
=
state
;
useEffect
(()
=>
{
dispatch
(
setBreadCrumbs
([
{
name
:
'
My Selection
'
,
link
:
'
/selection
'
},
{
name
:
'
Mint DOI
'
},
])
);
componentDidMount
()
{
this
.
retrieveSelectedDatasetsFromDatabase
();
}
async
function
fetchDatasetsAndUsers
()
{
const
datasets
=
await
axios
.
get
(
getDatasetsById
(
sessionId
,
datasetIds
));
getUsers
(
investigationIds
)
{
this
.
setState
({
fetching
:
true
,
}
);
const
investigationIds
=
datasets
.
data
.
map
((
d
)
=>
d
.
investigation
.
id
);
const
users
=
await
axios
.
get
(
getUsersByInvestigationIds
(
sessionId
,
[...
new
Set
(
investigationIds
)])
);
axios
.
get
(
getUsersByInvestigationIds
(
this
.
state
.
sessionId
,
investigationIds
))
.
then
((
res
)
=>
{
const
investigationUsers
=
res
.
data
;
this
.
setState
({
investigationUsers
,
fetching
:
false
,
fetched
:
true
,
});
})
.
catch
((
error
)
=>
{
console
.
log
(
error
);
});
}
retrieveSelectedDatasetsFromDatabase
()
{
/*if (!this.state.fetching) {
this.setState({
fetching: true
});
}*/
if
(
this
.
props
.
selection
.
datasetIds
.
length
>
0
)
{
axios
.
get
(
getDatasetsById
(
this
.
state
.
sessionId
,
this
.
props
.
selection
.
datasetIds
)
)
.
then
((
res
)
=>
{
try
{
const
datasets
=
res
.
data
;
this
.
setState
({
datasets
,
filtered
:
datasets
,
fetching
:
false
,
fetched
:
true
,
});
this
.
getUsers
(
uniq
(
datasets
.
map
((
o
)
=>
o
.
investigation
.
id
)));
}
catch
(
error
)
{
console
.
log
(
error
);
}
})
.
catch
((
error
)
=>
{
console
.
log
(
error
);
});
}
else
{
this
.
setState
({
datasets
:
[],
filtered
:
[],
fetching
:
false
,
setState
({
datasets
:
datasets
.
data
,
users
:
users
.
data
,
isFetching
:
false
,
});
}
}
render
()
{
/*if (this.props.selection.datasetIds.length !== this.state.datasets.length) {
this.retrieveSelectedDatasetsFromDatabase();
}*/
if
(
datasetIds
.
length
>
0
)
{
setState
({
datasets
:
[],
users
:
[],
isFetching
:
true
});
fetchDatasetsAndUsers
();
}
},
[
datasetIds
,
dispatch
,
sessionId
]);
return
(
<
Grid
fluid
style
=
{{
margin
:
60
}}
>
<
Row
className
=
"
show-grid
"
>
<
Col
xs
=
{
8
}
>
return
(
<
div
className
=
"
app__inner
"
>
<
Grid
fluid
>
<
Row
>
<
Col
md
=
{
7
}
>
<
Panel
bsStyle
=
"
primary
"
>
<
Panel
.
Heading
>
<
strong
>
Please
fill
in
this
form
<
/strong
>
<
/Panel.Heading
>
<
Panel
.
Body
>
{
this
.
state
.
fetching
?
(
{
fetching
?
(
<
Loader
message
=
"
Loading authors...
"
inPanel
/>
)
:
(
<
DOIForm
investigationUsers
=
{
this
.
state
.
investigationUsers
}
sessionId
=
{
this
.
props
.
user
.
sessionId
}
datasets
=
{
this
.
state
.
dataset
s
}
sessionId
=
{
sessionId
}
datasets
=
{
datasets
}
investigationUsers
=
{
user
s
}
/
>
)}
<
/Panel.Body
>
<
/Panel
>
<
/Col
>
<
Col
xs
=
{
4
}
>
<
Panel
bsStyle
=
"
primary
"
>
<
Col
md
=
{
5
}
>
<
Panel
bsStyle
=
"
info
"
>
<
Panel
.
Heading
>
<
strong
>
Dataset
List
<
/strong
>
<
/Panel.Heading
>
<
Panel
.
Body
>
<
BootstrapTable2
keyField
=
"
id
"
data
=
{
this
.
state
.
datasets
}
columns
=
{[
{
dataField
:
'
id
'
,
text
:
''
,
hidden
:
true
},
{
dataField
:
'
name
'
,
text
:
'
Name
'
},
{
dataField
:
'
investigationName
'
,
text
:
'
Proposal
'
},
{
dataField
:
'
definition
'
,
text
:
'
Technique
'
},
]}
pageOptions
=
{{
paginationSize
:
10
,
sizePerPage
:
25
,
showTotal
:
true
,
hidePageListOnlyOnePage
:
true
,
}}
striped
condensed
noDataIndication
=
"
This is no data to display
"
/>
{
fetching
?
(
<
Loader
message
=
"
Loading datasets...
"
inPanel
/>
)
:
(
<
BootstrapTable2
keyField
=
"
id
"
data
=
{
datasets
}
columns
=
{[
{
dataField
:
'
id
'
,
text
:
''
,
hidden
:
true
},
{
dataField
:
'
name
'
,
text
:
'
Name
'
},
{
dataField
:
'
investigation.name
'
,
text
:
'
Proposal
'
,
headerStyle
:
()
=>
({
width
:
120
}),
},
]}
pageOptions
=
{{
paginationSize
:
10
,
sizePerPage
:
25
,
showTotal
:
true
,
hidePageListOnlyOnePage
:
true
,
}}
striped
condensed
noDataIndication
=
"
This is no data to display
"
/>
)}
<
/Panel.Body
>
<
/Panel
>
<
/Col
>
<
/Row
>
<
/Grid
>
);
}
<
/div
>
);
}
function
mapStateToProps
(
state
)
{
return
{
user
:
state
.
user
,
events
:
state
.
events
,
selection
:
state
.
selection
,
};
}
function
mapDispatchToProps
(
dispatch
)
{
return
{
removeDatasetById
:
bindActionCreators
(
removeDatasetById
,
dispatch
),
addDatasetById
:
bindActionCreators
(
addDatasetById
,
dispatch
),
doSignIn
:
bindActionCreators
(
doSignIn
,
dispatch
),
};
}
MintSelectionPage
.
propTypes
=
{
perspective
:
PropTypes
.
oneOf
([
PERSPECTIVE
.
Datasets
,
PERSPECTIVE
.
Files
,
PERSPECTIVE
.
Events
,
]),
};
export
default
connect
(
mapStateToProps
,
mapDispatchToProps
)(
MintSelectionPage
);
export
default
MintSelectionPage
;
src/containers/Selection/SelectionPage.js
View file @
208cc9b7
import
axios
from
'
axios
'
;
import
PropTypes
from
'
prop-types
'
;
import
React
,
{
Component
}
from
'
react
'
;
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
{
Button
,
ButtonToolbar
,
...
...
@@ -8,150 +7,83 @@ import {
OverlayTrigger
,
Tooltip
,
}
from
'
react-bootstrap
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
bindActionCreators
}
from
'
redux
'
;
import
{
useSelector
,
useDispatch
}
from
'
react-redux
'
;
import
{
setBreadCrumbs
}
from
'
../../actions/breadcrumbs
'
;
import
{
doSignIn
,
doLogOut
}
from
'
../../actions/login
'
;
import
{
addDatasetById
,
removeDatasetById
}
from
'
../../actions/selection
'
;
import
{
getDatasetsById
}
from
'
../../api/icat-plus/catalogue
'
;
import
DatasetTable
from
'
../../components/Dataset/DatasetTable
'
;
import
Loader
from
'
../../components/Loader
'
;
import
{
PERSPECTIVE
}
from
'
../../constants
'
;
import
{
LinkContainer
}
from
'
react-router-bootstrap
'
;
class
SelectionPage
extends
Component
{
constructor
(
props
)
{
super
(
props
);
function
SelectionPage
()
{
const
sessionId
=
useSelector
((
state
)
=>
state
.
user
.
sessionId
);
const
datasetIds
=
useSelector
((
state
)
=>
state
.
selection
.
datasetIds
);
const
dispatch
=
useDispatch
();
this
.
state
=
{
investigationId
:
this
.
props
.
investigationId
,
username
:
this
.
props
.
user
.
username
,
sessionId
:
this
.
props
.
user
.
sessionId
,
datasets
:
[],
filtered
:
[],
fetching
:
true
,
datasetIds
:
this
.
props
.
selection
.
datasetIds
,
};
}
const
[
initialDatsetIds
]
=
useState
(
datasetIds
);
const
[
state
,
setState
]
=
useState
({
datasets
:
[],
isFetching
:
false
});
componentDidMount
()
{
this
.
retrieveSelectedDatasetsFromDatabase
();
this
.
props
.
setBreadCrumbs
([{
name
:
'
Selection
'
}]);
}
useEffect
(()
=>
{
dispatch
(
setBreadCrumbs
([{
name
:
'
My Selection
'
}]));
if
(
initialDatsetIds
.
length
>
0
)
{
setState
({
datasets
:
[],
isFetching
:
true
});
retrieveSelectedDatasetsFromDatabase
()
{
if
(
this
.
props
.
selection
.
datasetIds
.
length
>
0
)
{
axios
.
get
(
getDatasetsById
(
this
.
state
.
sessionId
,
this
.
props
.
selection
.
datasetIds
)
)
.
then
((
res
)
=>
{
this
.
setState
({
datasets
:
res
.
data
,
filtered
:
res
.
data
,
fetching
:
false
,
});
})
.
catch
((
error
)
=>
{
if
(
error
.
response
)
{
if
(
error
.
response
.
status
===
401
)
{
//this.props.doSignIn();
}
}
.
get
(
getDatasetsById
(
sessionId
,
initialDatsetIds
))
.
then
(({
data
})
=>
{
setState
({
datasets
:
data
,
isFetching
:
false
});
});
}
else
{
this
.
setState
({
datasets
:
[],
filtered
:
[],
fetching
:
false
,
});
}
}
render
()
{
if
(
this
.
props
.
user
.
sessionId
==
null
)
{
return
null
;
}
/** This means that datasets has not been loaded yet. It could be done with FETCHING (?) **/
},
[
initialDatsetIds
,
dispatch
,
sessionId
]);
/*if (this.props.selection.datasetIds.length !== this.state.datasets.length) {
this.retrieveSelectedDatasetsFromDatabase();
}*/
const
{
datasets
,
isFetching
:
fetching
}
=
state
;
const
tooltip
=
(
text
)
=>
<
Tooltip
id
=
"
tooltip
"
>
{
text
}
<
/Tooltip>
;
const
tooltip
=
(
text
)
=>
<
Tooltip
id
=
"
tooltip
"
>
{
text
}
<
/Tooltip>
;
return
(
<
div
>
<
ButtonToolbar
className
=
"
navbar-fixed-top
"
style
=
{{
backgroundColor
:
'
white
'
,
marginBottom
:
10
,
marginTop
:
100
}}
return
(
<
div
className
=
"
app__inner
"
>
<
ButtonToolbar
>
<
OverlayTrigger
placement
=
"
bottom
"
overlay
=
{
tooltip
(
'
Mint a DOI for all selected datasets
'
)}
>
<
div
style
=
{{
marginLeft
:
40
,
marginTop
:
10
}}
>
<
OverlayTrigger
placement
=
"
bottom
"
overlay
=
{
tooltip
(
'
Mint a DOI for all selected datasets
'
)}
>
<
Button
bsSize
=
"
small
"
bsStyle
=
"
primary
"
href
=
"
selection/mint
"
>
<
Glyphicon
glyph
=
"
plus
"
/>
Mint
a
DOI
<
/Button
>
<
/OverlayTrigger
>
<
OverlayTrigger
placement
=
"
bottom
"
overlay
=
{
tooltip
(
'
Download all selected datasets
'
)}
>
<
Button
style
=
{{
marginLeft
:
5
}}
bsSize
=
"
small
"
bsStyle
=
"
primary
"
target
=
"
_blank
"
>
<
Glyphicon
glyph
=
"
download
"
style
=
{{
marginRight
:
3
}}
/>{' '
}
Download
all
<
/Button
>
<
/OverlayTrigger
>
<
/div
>
<
/ButtonToolbar
>
<
div
style
=
{{
marginTop
:
60
}}
>
{
this
.
state
.
fetching
?
(
<
Loader
message
=
"
Loading datasets...
"
/>
)
:
(
<
DatasetTable
selection
=
{
this
.
props
.
selection
}
removeDatasetById
=
{
this
.
props
.
removeDatasetById
}
addDatasetById
=
{
this
.
props
.
addDatasetById
}