Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
nomad-lab
nomad-FAIR
Commits
4baa45cc
Commit
4baa45cc
authored
Apr 02, 2019
by
Markus Scheidgen
Browse files
Refactored loading, downloading, archive view.
parent
804614ba
Changes
11
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
4baa45cc
...
...
@@ -56,6 +56,7 @@ your browser.
## Change log
### v0.4.4
-
improved GUI navigation
-
support for multiple domains
-
info API endpoint
...
...
gui/src/components/ArchiveCalcView.js
View file @
4baa45cc
import
React
from
'
react
'
import
PropTypes
from
'
prop-types
'
import
{
withStyles
,
LinearProgress
,
Fab
}
from
'
@material-ui/core
'
import
{
withStyles
,
Fab
,
Card
,
CardContent
}
from
'
@material-ui/core
'
import
ReactJson
from
'
react-json-view
'
import
{
compose
}
from
'
recompose
'
import
{
withErrors
}
from
'
./errors
'
...
...
@@ -19,23 +19,22 @@ class ArchiveCalcView extends React.Component {
}
static
styles
=
theme
=>
({
root
:
{
display
:
'
flex
'
,
flexDirection
:
'
column
'
,
height
:
'
100%
'
},
root
:
{},
metaInfo
:
{
flex
:
'
0 0 auto
'
,
overflowY
:
'
auto
'
height
:
'
20vh
'
,
overflowY
:
'
auto
'
,
marginTop
:
theme
.
spacing
.
unit
*
3
,
marginBottom
:
theme
.
spacing
.
unit
*
3
},
data
:
{
flex
:
'
1 1
'
height
:
'
60vh
'
,
overflowY
:
'
auto
'
},
downloadFab
:
{
position
:
'
absolute
'
,
zIndex
:
1
,
top
:
theme
.
spacing
.
unit
,
right
:
theme
.
spacing
.
unit
*
3
right
:
32
,
bottom
:
32
,
position
:
'
fixed !important
'
}
});
...
...
@@ -79,6 +78,30 @@ class ArchiveCalcView extends React.Component {
return
(
<
div
className
=
{
classes
.
root
}
>
<
Card
className
=
{
classes
.
metaInfo
}
>
<
CardContent
>
{
showMetaInfo
&&
metaInfo
?
metaInfoData
?
<
Markdown
>
{
`**
${
metaInfoData
.
name
}
**:
${
metaInfoData
.
description
}
`
}
<
/Markdown
>
:
<
Markdown
>
This
value
has
**
no
**
*
meta
-
info
*
attached
to
it
.
<
/Markdown
>
:
<
Markdown
>
Click
a
value
to
show
its
*
meta
-
info
*!<
/Markdown
>
}
<
/CardContent
>
<
/Card
>
<
Card
className
=
{
classes
.
data
}
>
<
CardContent
>
{
data
?
<
ReactJson
src
=
{
this
.
state
.
data
}
enableClipboard
=
{
false
}
collapsed
=
{
2
}
displayObjectSize
=
{
false
}
onSelect
=
{
this
.
handleShowMetaInfo
.
bind
(
this
)}
/
>
:
''
}
<
/CardContent
>
<
/Card
>
<
Download
classes
=
{{
root
:
classes
.
downloadFab
}}
tooltip
=
"
download calculation archive
"
component
=
{
Fab
}
className
=
{
classes
.
downloadFab
}
color
=
"
primary
"
size
=
"
medium
"
...
...
@@ -86,24 +109,6 @@ class ArchiveCalcView extends React.Component {
>
<
DownloadIcon
/>
<
/Download
>
<
div
className
=
{
classes
.
data
}
>
{
data
?
<
ReactJson
src
=
{
this
.
state
.
data
}
enableClipboard
=
{
false
}
collapsed
=
{
4
}
displayObjectSize
=
{
false
}
onSelect
=
{
this
.
handleShowMetaInfo
.
bind
(
this
)}
/
>
:
<
LinearProgress
variant
=
"
query
"
/>
}
<
/div
>
<
div
className
=
{
classes
.
metaInfo
}
>
{
showMetaInfo
&&
metaInfo
?
metaInfoData
?
<
Markdown
>
{
`**
${
metaInfoData
.
name
}
**:
${
metaInfoData
.
description
}
`
}
<
/Markdown
>
:
<
Markdown
>
This
value
has
**
no
**
*
meta
-
info
*
attached
to
it
.
<
/Markdown
>
:
<
Markdown
>
Click
a
value
to
show
its
*
meta
-
info
*!<
/Markdown
>
}
<
/div
>
<
/div
>
)
}
...
...
gui/src/components/ArchiveLogView.js
View file @
4baa45cc
import
React
from
'
react
'
import
PropTypes
from
'
prop-types
'
import
{
withStyles
,
LinearProgress
,
Fab
}
from
'
@material-ui/core
'
import
{
withStyles
,
Fab
}
from
'
@material-ui/core
'
import
{
compose
}
from
'
recompose
'
import
{
withErrors
}
from
'
./errors
'
import
{
withApi
}
from
'
./api
'
...
...
@@ -23,10 +23,10 @@ class ArchiveLogView extends React.Component {
}
},
downloadFab
:
{
position
:
'
absolute
'
,
zIndex
:
1
,
top
:
theme
.
spacing
.
unit
,
right
:
theme
.
spacing
.
unit
*
3
right
:
32
,
bottom
:
32
,
position
:
'
fixed !important
'
}
});
...
...
@@ -53,6 +53,8 @@ class ArchiveLogView extends React.Component {
return
(
<
div
className
=
{
classes
.
root
}
>
<
pre
>
{
data
||
'
empty log
'
}
<
/pre
>
<
Download
classes
=
{{
root
:
classes
.
downloadFab
}}
tooltip
=
"
download logfile
"
component
=
{
Fab
}
className
=
{
classes
.
downloadFab
}
color
=
"
primary
"
size
=
"
medium
"
...
...
@@ -60,11 +62,6 @@ class ArchiveLogView extends React.Component {
>
<
DownloadIcon
/>
<
/Download
>
{
data
!==
null
?
<
pre
>
{
data
||
'
empty log
'
}
<
/pre
>
:
<
LinearProgress
variant
=
"
query
"
/>
}
<
/div
>
)
}
...
...
gui/src/components/Calc.js
View file @
4baa45cc
import
React
from
'
react
'
import
PropTypes
from
'
prop-types
'
import
{
withStyles
,
Tab
,
Tabs
}
from
'
@material-ui/core
'
import
SwipeableViews
from
'
react-swipeable-views
'
import
ArchiveCalcView
from
'
./ArchiveCalcView
'
import
ArchiveLogView
from
'
./ArchiveLogView
'
import
RepoCalcView
from
'
./RepoCalcView
'
...
...
@@ -47,9 +46,15 @@ class Calc extends React.Component {
<
/Tabs
>
<
div
className
=
{
classes
.
content
}
>
{
viewIndex
===
0
&&
<
RepoCalcView
{...
calcProps
}
/>
}
{
viewIndex
===
1
&&
<
ArchiveCalcView
{...
calcProps
}
/>
}
{
viewIndex
===
2
&&
<
ArchiveLogView
{...
calcProps
}
/>
}
<
div
style
=
{
viewIndex
!==
0
?
{
display
:
'
none
'
}
:
{}}
>
<
RepoCalcView
{...
calcProps
}
/
>
<
/div
>
<
div
style
=
{
viewIndex
!==
1
?
{
display
:
'
none
'
}
:
{}}
>
<
ArchiveCalcView
{...
calcProps
}
/
>
<
/div
>
<
div
style
=
{
viewIndex
!==
2
?
{
display
:
'
none
'
}
:
{}}
>
<
ArchiveLogView
{...
calcProps
}
/
>
<
/div
>
<
/div
>
<
/div
>
)
...
...
gui/src/components/Markdown.js
View file @
4baa45cc
...
...
@@ -42,6 +42,9 @@ var styles = theme => ({
fontSize
:
14
,
lineHeight
:
1.6
},
'
& p:first-child
'
:
{
marginTop
:
0
},
'
& h1
'
:
(
0
,
extend
)({},
theme
.
typography
.
h3
,
{
color
:
theme
.
palette
.
text
.
primary
,
margin
:
'
32px 0 16px
'
...
...
gui/src/components/Navigation.js
View file @
4baa45cc
...
...
@@ -23,11 +23,12 @@ import ChevronLeftIcon from '@material-ui/icons/ChevronLeft'
import
MenuIcon
from
'
@material-ui/icons/Menu
'
import
{
Link
,
withRouter
}
from
'
react-router-dom
'
import
{
compose
}
from
'
recompose
'
import
{
MuiThemeProvider
,
IconButton
,
Checkbox
,
FormLabel
}
from
'
@material-ui/core
'
import
{
MuiThemeProvider
,
IconButton
,
Checkbox
,
FormLabel
,
LinearProgress
}
from
'
@material-ui/core
'
import
{
genTheme
,
repoTheme
,
archiveTheme
,
encTheme
,
analyticsTheme
}
from
'
../config
'
import
classNames
from
'
classnames
'
import
{
HelpContext
}
from
'
./help
'
import
LoginLogout
from
'
./LoginLogout
'
import
{
withApi
}
from
'
./api
'
const
drawerWidth
=
200
...
...
@@ -59,7 +60,8 @@ class Navigation extends React.Component {
static
propTypes
=
{
classes
:
PropTypes
.
object
.
isRequired
,
children
:
PropTypes
.
any
,
location
:
PropTypes
.
object
.
isRequired
location
:
PropTypes
.
object
.
isRequired
,
loading
:
PropTypes
.
number
.
isRequired
}
static
styles
=
theme
=>
({
...
...
@@ -262,7 +264,7 @@ class Navigation extends React.Component {
}
render
()
{
const
{
classes
,
children
,
location
:
{
pathname
}
}
=
this
.
props
const
{
classes
,
children
,
location
:
{
pathname
}
,
loading
}
=
this
.
props
const
drawer
=
(
<
Drawer
variant
=
"
permanent
"
...
...
@@ -324,6 +326,7 @@ class Navigation extends React.Component {
}
<
/HelpContext.Consumer
>
<
/div
>
<
/Toolbar
>
{
loading
?
<
LinearProgress
color
=
"
secondary
"
/>
:
''
}
<
/AppBar
>
<
/MuiThemeProvider
>
{
drawer
}
...
...
@@ -339,4 +342,4 @@ class Navigation extends React.Component {
}
}
export
default
compose
(
withRouter
,
withStyles
(
Navigation
.
styles
))(
Navigation
)
export
default
compose
(
withRouter
,
withApi
(
false
),
withStyles
(
Navigation
.
styles
))(
Navigation
)
gui/src/components/Repo.js
View file @
4baa45cc
...
...
@@ -7,14 +7,14 @@ import TableCell from '@material-ui/core/TableCell'
import
TablePagination
from
'
@material-ui/core/TablePagination
'
import
TableRow
from
'
@material-ui/core/TableRow
'
import
Paper
from
'
@material-ui/core/Paper
'
import
{
TableHead
,
LinearProgress
,
FormControl
,
FormControlLabel
,
Checkbox
,
FormGroup
,
import
{
TableHead
,
FormControl
,
FormControlLabel
,
Checkbox
,
FormGroup
,
FormLabel
,
IconButton
,
MuiThemeProvider
,
Typography
,
Tooltip
,
TableSortLabel
,
ExpansionPanelDetails
,
ExpansionPanelSummary
,
ExpansionPanel
,
Grid
}
from
'
@material-ui/core
'
import
{
compose
}
from
'
recompose
'
import
{
withErrors
}
from
'
./errors
'
import
AnalyticsIcon
from
'
@material-ui/icons/Settings
'
import
{
analyticsTheme
}
from
'
../config
'
import
Link
from
'
react-router-dom/Link
'
import
{
withApi
}
from
'
./api
'
import
{
withApi
,
DisableOnLoading
}
from
'
./api
'
import
PeriodicTable
from
'
./PeriodicTable
'
import
ExpandMoreIcon
from
'
@material-ui/icons/ExpandMore
'
import
QuantityHistogram
from
'
./QuantityHistogram
'
...
...
@@ -150,21 +150,20 @@ class Repo extends React.Component {
page
:
1
,
rowsPerPage
:
10
,
total
:
0
,
loading
:
true
,
owner
:
'
all
'
,
sortedBy
:
'
formula
'
,
sortOrder
:
'
asc
'
,
searchValues
:
{},
aggregations
:
{},
metrics
:
{},
metric
:
'
code_runs
'
metric
:
'
code_runs
'
,
useMetric
:
'
code_runs
'
}
update
(
changes
)
{
changes
=
changes
||
{}
const
{
page
,
rowsPerPage
,
owner
,
sortedBy
,
sortOrder
,
searchValues
,
metric
}
=
{...
this
.
state
,
...
changes
}
delete
changes
.
metric
this
.
setState
({
loading
:
true
,
...
changes
})
this
.
setState
({...
changes
})
// code_runs is returned anyways
const
metrics_to_retrieve
=
metric
===
'
code_runs
'
?
[]
:
[
metric
]
...
...
@@ -188,12 +187,12 @@ class Repo extends React.Component {
rowsPerPage
:
per_page
,
total
:
total
,
loading
:
false
,
owner
:
owner
,
metric
:
metric
metric
:
metric
,
useMetric
:
metric
})
}).
catch
(
errors
=>
{
this
.
setState
({
data
:
[],
total
:
0
,
loading
:
false
,
owner
:
owner
})
this
.
setState
({
data
:
[],
total
:
0
,
owner
:
owner
})
this
.
props
.
raiseError
(
errors
)
})
}
...
...
@@ -269,174 +268,176 @@ class Repo extends React.Component {
render
()
{
const
{
classes
,
user
}
=
this
.
props
const
{
data
,
rowsPerPage
,
page
,
total
,
loading
,
sortedBy
,
sortOrder
,
searchValues
,
aggregations
,
metrics
,
m
etric
}
=
this
.
state
const
{
data
,
rowsPerPage
,
page
,
total
,
sortedBy
,
sortOrder
,
searchValues
,
aggregations
,
metrics
,
useM
etric
}
=
this
.
state
const
emptyRows
=
rowsPerPage
-
Math
.
min
(
rowsPerPage
,
total
-
(
page
-
1
)
*
rowsPerPage
)
const
quantity
=
(
key
,
title
)
=>
(
<
QuantityHistogram
classes
=
{{
root
:
classes
.
quantity
}}
title
=
{
title
||
key
}
width
=
{
300
}
data
=
{
aggregations
[
key
]}
metric
=
{
m
etric
}
data
=
{
aggregations
[
key
]}
metric
=
{
useM
etric
}
value
=
{
searchValues
[
key
]}
onChanged
=
{(
selection
)
=>
this
.
handleQuantityChanged
(
key
,
selection
)}
/>
)
const
ownerLabel
=
{
all
:
'
All calculations
'
,
user
:
'
Your calculations
'
,
staging
:
'
Only calculations from your staging area
'
all
:
'
All entries
'
,
public
:
'
Only public entries
'
,
user
:
'
Only your entries
'
,
staging
:
'
Only entries from your staging area
'
}
const
metricsLabel
=
{
code_runs
:
'
Code run
s
'
,
code_runs
:
'
Entrie
s
'
,
total_energies
:
'
Total energy calculations
'
,
geometries
:
'
Unique geometries
'
,
datasets
:
'
Datasets
'
,
unique_code_runs
:
'
Unique
code run
s
'
unique_code_runs
:
'
Unique
entrie
s
'
}
return
(
<
div
className
=
{
classes
.
root
}
>
{
user
?
<
FormControl
>
<
FormLabel
>
Filter
calculations
and
only
show
:
<
/FormLabel
>
<
FormGroup
row
>
{[
'
all
'
,
'
user
'
,
'
staging
'
].
map
(
owner
=>
(
<
FormControlLabel
key
=
{
owner
}
control
=
{
<
Checkbox
checked
=
{
this
.
state
.
owner
===
owner
}
onChange
=
{()
=>
this
.
handleOwnerChange
(
owner
)}
value
=
"
owner
"
/>
}
label
=
{
ownerLabel
[
owner
]}
/
>
))}
<
/FormGroup
>
<
/FormControl> : '
'
}
<
DisableOnLoading
>
{
user
?
<
FormControl
>
<
FormLabel
>
Filter
entries
and
show
:
<
/FormLabel
>
<
FormGroup
row
>
{[
'
all
'
,
'
public
'
,
'
user
'
,
'
staging
'
].
map
(
owner
=>
(
<
FormControlLabel
key
=
{
owner
}
control
=
{
<
Checkbox
checked
=
{
this
.
state
.
owner
===
owner
}
onChange
=
{()
=>
this
.
handleOwnerChange
(
owner
)}
value
=
"
owner
"
/>
}
label
=
{
ownerLabel
[
owner
]}
/
>
))}
<
/FormGroup
>
<
/FormControl> : '
'
}
<
div
className
=
{
classes
.
searchBarContainer
}
>
<
SearchBar
fullWidth
fullWidthInput
=
{
false
}
label
=
"
search
"
placeholder
=
"
enter atoms or other quantities
"
aggregations
=
{
aggregations
}
values
=
{
searchValues
}
metric
=
{
m
etric
}
onChanged
=
{
values
=>
this
.
handleSearchChanged
(
values
)}
/
>
<
/div
>
<
div
className
=
{
classes
.
searchBarContainer
}
>
<
SearchBar
fullWidth
fullWidthInput
=
{
false
}
label
=
"
search
"
placeholder
=
"
enter atoms or other quantities
"
aggregations
=
{
aggregations
}
values
=
{
searchValues
}
metric
=
{
useM
etric
}
onChanged
=
{
values
=>
this
.
handleSearchChanged
(
values
)}
/
>
<
/div
>
<
ExpansionPanel
>
<
ExpansionPanelSummary
expandIcon
=
{
<
ExpandMoreIcon
/>
}
className
=
{
classes
.
searchSummary
}
>
<
Typography
variant
=
"
h6
"
style
=
{{
textAlign
:
'
center
'
,
width
:
'
100%
'
,
fontWeight
:
'
normal
'
}}
>
Found
<
b
>
{
metrics
.
code_runs
}
<
/b>{
m
etric === 'unique_code_runs'
?
(
<span>
(
<b>{metrics.unique_code_runs}</
b
>
unique
)
<
/span>
)
: ''} code run
s
{
m
etric
===
'
geometries
'
?
(
<
span
>
that
simulate
<
b
>
{
metrics
.
geometries
}
<
/b> unique geometries</
span
>
)
:
''
}
{
m
etric
===
'
total_energies
'
?
(
<
span
>
with
<
b
>
{
metrics
.
total_energies
}
<
/b> total energy calculations</
span
>
)
:
''
}
{
m
etric
===
'
datasets
'
?
(
<
span
>
curated
in
<
b
>
{
metrics
.
datasets
}
<
/b> datasets</
span
>
)
:
''
}.
<
/Typography
>
<
/ExpansionPanelSummary
>
<
ExpansionPanelDetails
className
=
{
classes
.
searchDetails
}
>
<
div
className
=
{
classes
.
statistics
}
>
<
FormControl
>
<
FormLabel
>
Metric
used
in
statistics
:
<
/FormLabel
>
<
FormGroup
row
>
{[
'
code_runs
'
,
'
unique_code_runs
'
,
'
total_energies
'
,
'
geometries
'
,
'
datasets
'
].
map
(
metric
=>
(
<
FormControlLabel
key
=
{
metric
}
control
=
{
<
Checkbox
checked
=
{
this
.
state
.
metric
===
metric
}
onChange
=
{()
=>
this
.
handleMetricChange
(
metric
)}
value
=
{
metric
}
/
>
}
label
=
{
metricsLabel
[
metric
]}
/
>
))}
<
/FormGroup
>
<
/FormControl
>
<
/div
>
<
ExpansionPanel
>
<
ExpansionPanelSummary
expandIcon
=
{
<
ExpandMoreIcon
/>
}
className
=
{
classes
.
searchSummary
}
>
<
Typography
variant
=
"
h6
"
style
=
{{
textAlign
:
'
center
'
,
width
:
'
100%
'
,
fontWeight
:
'
normal
'
}}
>
Found
<
b
>
{
metrics
.
code_runs
}
<
/b>{
useM
etric === 'unique_code_runs'
?
(
<span>
(
<b>{metrics.unique_code_runs}</
b
>
unique
)
<
/span>
)
: ''} code run
s
{
useM
etric
===
'
geometries
'
?
(
<
span
>
that
simulate
<
b
>
{
metrics
.
geometries
}
<
/b> unique geometries</
span
>
)
:
''
}
{
useM
etric
===
'
total_energies
'
?
(
<
span
>
with
<
b
>
{
metrics
.
total_energies
}
<
/b> total energy calculations</
span
>
)
:
''
}
{
useM
etric
===
'
datasets
'
?
(
<
span
>
curated
in
<
b
>
{
metrics
.
datasets
}
<
/b> datasets</
span
>
)
:
''
}.
<
/Typography
>
<
/ExpansionPanelSummary
>
<
ExpansionPanelDetails
className
=
{
classes
.
searchDetails
}
>
<
div
className
=
{
classes
.
statistics
}
>
<
FormControl
>
<
FormLabel
>
Metric
used
in
statistics
:
<
/FormLabel
>
<
FormGroup
row
>
{[
'
code_runs
'
,
'
unique_code_runs
'
,
'
total_energies
'
,
'
geometries
'
,
'
datasets
'
].
map
(
metric
=>
(
<
FormControlLabel
key
=
{
metric
}
control
=
{
<
Checkbox
checked
=
{
this
.
state
.
metric
===
metric
}
onChange
=
{()
=>
this
.
handleMetricChange
(
metric
)}
value
=
{
metric
}
/
>
}
label
=
{
metricsLabel
[
metric
]}
/
>
))}
<
/FormGroup
>
<
/FormControl
>
<
/div
>
<
PeriodicTable
aggregations
=
{
aggregations
.
atoms
}
metric
=
{
m
etric
}
values
=
{
searchValues
.
atoms
||
[]}
onChanged
=
{(
selection
)
=>
this
.
handleAtomsChanged
(
selection
)}
/
>
<
PeriodicTable
aggregations
=
{
aggregations
.
atoms
}
metric
=
{
useM
etric
}
values
=
{
searchValues
.
atoms
||
[]}
onChanged
=
{(
selection
)
=>
this
.
handleAtomsChanged
(
selection
)}
/
>
<
Grid
container
spacing
=
{
24
}
className
=
{
classes
.
quantityGrid
}
>
<
Grid
container
spacing
=
{
24
}
className
=
{
classes
.
quantityGrid
}
>
<
Grid
item
xs
=
{
4
}
>
{
quantity
(
'
system
'
,
'
System
'
)}
{
quantity
(
'
crystal_system
'
,
'
Crystal system
'
)}
<
/Grid
>
<
Grid
item
xs
=
{
4
}
>
{
quantity
(
'
basis_set
'
,
'
Basis set
'
)}
{
quantity
(
'
xc_functional
'
,
'
XC functionals
'
)}
<
/Grid
>
<
Grid
item
xs
=
{
4
}
>
{
quantity
(
'
code_name
'
,
'
Code
'
)}
<
Grid
item
xs
=
{
4
}
>
{
quantity
(
'
system
'
,
'
System
'
)}
{
quantity
(
'
crystal_system
'
,
'
Crystal system
'
)}
<
/Grid
>
<
Grid
item
xs
=
{
4
}
>
{
quantity
(
'
basis_set
'
,
'
Basis set
'
)}
{
quantity
(
'
xc_functional
'
,
'
XC functionals
'
)}
<
/Grid
>
<
Grid
item
xs
=
{
4
}
>
{
quantity
(
'
code_name
'
,
'
Code
'
)}
<
/Grid
>
<
/Grid
>
<
/Grid
>
<
/ExpansionPanelDetails
>
<
/ExpansionPanel
>
<
/ExpansionPanelDetails
>
<
/ExpansionPanel
>
<
FormGroup
className
=
{
classes
.
selectFormGroup
}
row
>
<
FormLabel
classes
=
{{
root
:
classes
.
selectLabel
}}
style
=
{{
flexGrow
:
1
}}
>
<
FormGroup
className
=
{
classes
.
selectFormGroup
}
row
>
<
FormLabel
classes
=
{{
root
:
classes
.
selectLabel
}}
style
=
{{
flexGrow
:
1
}}
>
<
/FormLabel
>
<
FormLabel
classes
=
{{
root
:
classes
.
selectLabel
}}
>
<
/FormLabel
>
<
FormLabel
classes
=
{{
root
:
classes
.
selectLabel
}}
>
Analyse
{
total
}
code
runs
in
an
analytics
notebook
<
/FormLabel
>
<
MuiThemeProvider
theme
=
{
analyticsTheme
}
>
<
IconButton
color
=
"
primary
"
component
=
{
Link
}
to
=
{
`/analytics`
}
>
<
AnalyticsIcon
/>
<
/IconButton
>
<
/MuiThemeProvider
>
<
/FormGroup
>
<
/FormLabel
>
<
MuiThemeProvider
theme
=
{
analyticsTheme
}
>
<
IconButton
color
=
"
primary
"
component
=
{
Link
}
to
=
{
`/analytics`
}
>
<
AnalyticsIcon
/>
<
/IconButton
>
<
/MuiThemeProvider
>
<
/FormGroup
>
<
Paper
className
=
{
classes
.
data
}
>
{
loading
?
<
LinearProgress
variant
=
"
query
"
/>
:
<
div
className
=
{
classes
.
progressPlaceholder
}
/>
}
<
Table
>
<
TableHead
>
<
TableRow
>
{
Object
.
keys
(
this
.
rowConfig
).
map
(
key
=>
(
<
TableCell
padding
=
"
dense
"
key
=
{
key
}
>
<
Tooltip
title
=
"
Sort
"
placement
=
{
'
bottom-start
'
}
enterDelay
=
{
300
}
>
<
TableSortLabel
active
=
{
sortedBy
===
key
}
direction
=
{
sortOrder
}
onClick
=
{()
=>
this
.
handleSort
(
key
)}
<
Paper
className
=
{
classes
.
data
}
>
<
Table
>
<
TableHead
>
<
TableRow
>
{
Object
.
keys
(
this
.
rowConfig
).
map
(
key
=>
(
<
TableCell
padding
=
"
dense
"
key
=
{
key
}
>
<
Tooltip
title
=
"
Sort
"
placement
=
{
'
bottom-start
'
}
enterDelay
=
{
300
}
>
{
this
.
rowConfig
[
key
].
label
}
<
/TableSortLabel
>
<
/Tooltip
>
<
/TableCell
>
))}
<
/TableRow
>
<
/TableHead
>
<
TableBody
>
{
data
.
map
((
calc
,
index
)
=>
(
<
TableRow
hover
tabIndex
=
{
-
1
}
key
=
{
index
}
className
=
{
classes
.
clickableRow
}
>
{
Object
.
keys
(
this
.
rowConfig
).
map
((
key
,
rowIndex
)
=>
(
<
TableCell
padding
=
"
dense
"
key
=
{
rowIndex
}
onClick
=
{()
=>
this
.
handleClickCalc
(
calc
)}
>
{
this
.
renderCell
(
key
,
this
.
rowConfig
[
key
],
calc
)}
<
TableSortLabel
active
=
{
sortedBy
===
key
}
direction
=
{
sortOrder
}
onClick
=
{()
=>
this
.
handleSort
(
key
)}
>
{
this
.
rowConfig
[
key
].
label
}
<
/TableSortLabel
>
<
/Tooltip
>
<
/TableCell
>
))}
<
/TableRow
>
))}
{
emptyRows
>
0
&&
(
<
TableRow
style
=
{{
height
:
57
*
emptyRows
}}
>
<
TableCell
colSpan
=
{
6
}
/
>
<
/TableHead
>
<
TableBody
>
{
data
.
map
((
calc
,
index
)
=>
(
<
TableRow
hover
tabIndex
=
{
-
1
}
key
=
{
index
}
className
=
{
classes
.
clickableRow
}
>
{
Object
.
keys
(
this
.
rowConfig
).
map
((
key
,
rowIndex
)
=>
(
<
TableCell
padding
=
"
dense
"
key
=
{
rowIndex
}
onClick
=
{()
=>
this
.
handleClickCalc
(
calc
)}
>
{
this
.
renderCell
(
key
,
this
.
rowConfig
[
key
],
calc
)}
<
/TableCell
>
))}
<
/TableRow
>
))}
{
emptyRows
>
0
&&
(
<
TableRow
style
=
{{
height
:
57
*
emptyRows
}}
>
<
TableCell
colSpan
=
{
6
}
/
>
<
/TableRow
>
)}
<
TableRow
>
<
TablePagination
count
=
{
total
}
rowsPerPage
=
{
rowsPerPage
}
page
=
{
page
-
1
}
backIconButtonProps
=
{{
'
aria-label
'
:
'
Previous Page
'
}}
nextIconButtonProps
=
{{
'
aria-label
'
:
'
Next Page
'
}}
onChangePage
=
{
this
.
handleChangePage
}
onChangeRowsPerPage
=
{
this
.
handleChangeRowsPerPage
}
/
>
<
/TableRow
>
)}
<
TableRow
>
<
TablePagination
count
=
{
total
}
rowsPerPage
=
{
rowsPerPage
}
page
=
{
page
-
1
}
backIconButtonProps
=
{{
'
aria-label
'
:
'
Previous Page
'
}}
nextIconButtonProps
=
{{
'
aria-label
'
:
'
Next Page
'