Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ICAT
Datahub
Commits
b51c8e62
Commit
b51c8e62
authored
Jun 14, 2021
by
Alejandro De Maria Antolinos
Browse files
It fixes
#506
parent
fabeb39a
Pipeline
#48584
passed with stage
in 2 minutes and 53 seconds
Changes
14
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/App.js
View file @
b51c8e62
...
...
@@ -23,6 +23,7 @@ import EventsPage from './containers/EventsPage';
import
SelectionPage
from
'
./containers/Selection/SelectionPage
'
;
import
CameraPage
from
'
./containers/CameraPage
'
;
import
DataStatisticsPage
from
'
./containers/DataStatisticsPage
'
;
import
LogbookStatisticsPage
from
'
./containers/LogbookStatsPage
'
;
import
MintSelectionPage
from
'
./containers/Selection/MintSelectionPage
'
;
import
BeamlineDataPage
from
'
./containers/BeamlineData/BeamlineDataPage
'
;
import
{
getRemainingSessionTime
}
from
'
./helpers/auth
'
;
...
...
@@ -196,6 +197,12 @@ function App() {
<
/Route
>
)}
{
user
.
isAdministrator
&&
(
<
Route
exact
path
=
"
/manager/stats/logbook
"
>
<
LogbookStatisticsPage
/>
<
/Route
>
)}
<
Route
exact
path
=
"
/login
"
>
<
Redirect
to
=
{
...
...
src/api/icat-plus/logbook.js
View file @
b51c8e62
...
...
@@ -29,6 +29,30 @@ export function getEventURL(
return
`
${
ICATPLUS
.
server
}
/logbook/
${
sessionId
}
/event?
${
params
.
toString
()}
`
;
}
export
function
getLogbookStatisticsURL
(
sessionId
,
startDate
,
endDate
)
{
const
params
=
new
URLSearchParams
();
params
.
set
(
'
startDate
'
,
startDate
);
params
.
set
(
'
endDate
'
,
endDate
);
return
`
${
ICATPLUS
.
server
}
/logbook/
${
sessionId
}
/stats/investigation?
${
params
.
toString
()}
`
;
}
export
function
getCountLogbookStatisticsURL
(
sessionId
,
startDate
,
endDate
,
type
)
{
const
params
=
new
URLSearchParams
();
params
.
set
(
'
startDate
'
,
startDate
);
params
.
set
(
'
endDate
'
,
endDate
);
params
.
set
(
'
type
'
,
type
);
return
`
${
ICATPLUS
.
server
}
/logbook/
${
sessionId
}
/stats/count?
${
params
.
toString
()}
`
;
}
/** Get the tags associated to a given investigation
* @param {string} sessionId session identifier
* @param {*} investigationId investigation identifier
...
...
src/components/ManagerStats/GeneralStats/Logbook/AnnotationsStatisticsPanel.js
0 → 100644
View file @
b51c8e62
import
React
from
'
react
'
;
import
{
Grid
,
Row
,
Col
}
from
'
react-bootstrap
'
;
import
ParameterTableWidget
from
'
../../../Instrument/ParameterTableWidget
'
;
function
AnnotationsStatisticsPanel
(
props
)
{
const
{
statistics
}
=
props
;
const
investigations
=
statistics
!==
null
?
statistics
.
filter
((
stats
)
=>
stats
.
annotations
>
0
)
:
0
;
// Count notifications and annotations
const
annotationsListCount
=
statistics
.
map
((
record
)
=>
record
.
annotations
?
record
.
annotations
:
0
);
// Calculate sum
const
annotationsCount
=
annotationsListCount
.
length
>
0
?
annotationsListCount
.
reduce
((
a
,
b
)
=>
a
+
b
)
:
0
;
/** Get maximum and minimum */
const
maxAnnotations
=
Math
.
max
(...
annotationsListCount
);
return
(
<
Grid
fluid
style
=
{{
margin
:
20
}}
>
<
Row
>
<
Col
xs
=
{
12
}
>
<
h4
>
Annotations
<
/h4
>
<
ParameterTableWidget
striped
parameters
=
{[
{
name
:
'
Investigation with Annotations
'
,
value
:
investigations
.
length
,
},
{
name
:
'
Total Annotations
'
,
value
:
annotationsCount
,
},
{
name
:
'
Max. Annotations/investigation
'
,
value
:
maxAnnotations
,
},
]}
/
>
<
/Col
>
<
/Row
>
<
/Grid
>
);
}
export
default
AnnotationsStatisticsPanel
;
src/components/ManagerStats/GeneralStats/Logbook/LogbookInvestigationStatisticsPanel.js
0 → 100644
View file @
b51c8e62
import
React
from
'
react
'
;
import
{
Grid
,
Row
,
Col
}
from
'
react-bootstrap
'
;
import
ParameterTableWidget
from
'
../../../Instrument/ParameterTableWidget
'
;
function
LogbookInvestigationStatisticsPanel
(
props
)
{
const
{
statistics
}
=
props
;
const
instruments
=
new
Set
(
statistics
.
map
((
i
)
=>
i
.
instrument
));
const
reducer
=
(
a
,
b
)
=>
{
return
{
count
:
a
.
count
+
b
.
count
,
};
};
// Total events
const
total
=
statistics
.
length
>
0
?
statistics
.
reduce
(
reducer
).
count
:
0
;
// Count notifications and annotations
const
annotationsListCount
=
statistics
.
map
((
record
)
=>
record
.
annotations
?
record
.
annotations
:
0
);
const
notificationsListCount
=
statistics
.
map
((
record
)
=>
record
.
notifications
?
record
.
notifications
:
0
);
// Calculate sum
const
annotationsCount
=
annotationsListCount
.
length
>
0
?
annotationsListCount
.
reduce
((
a
,
b
)
=>
a
+
b
)
:
0
;
const
notificationsCount
=
notificationsListCount
.
length
>
0
?
notificationsListCount
.
reduce
((
a
,
b
)
=>
a
+
b
)
:
0
;
/** Get maximum and minimum */
const
maxAnnotations
=
Math
.
max
(...
annotationsListCount
);
const
maxNotifications
=
Math
.
max
(...
notificationsListCount
);
return
(
<
Grid
fluid
style
=
{{
margin
:
20
}}
>
<
Row
>
<
Col
xs
=
{
12
}
>
<
h4
>
General
<
/h4
>
<
ParameterTableWidget
striped
parameters
=
{[
{
name
:
'
Instruments
'
,
value
:
instruments
.
size
,
},
{
name
:
'
Investigations
'
,
value
:
statistics
.
length
,
},
{
name
:
'
Average Events/Investigations
'
,
value
:
parseFloat
(
total
/
statistics
.
length
).
toFixed
(
0
),
},
{
name
:
'
Max. Annotation/investigation
'
,
value
:
maxAnnotations
,
},
{
name
:
'
Max. Notifications/investigation
'
,
value
:
maxNotifications
,
},
{
name
:
'
Total Events
'
,
value
:
total
,
},
]}
/
>
<
h4
>
Event
types
<
/h4
>
<
ParameterTableWidget
striped
parameters
=
{[
{
name
:
'
Annotations
'
,
value
:
`
${
annotationsCount
}
(
${
parseFloat
(
annotationsCount
/
total
).
toFixed
(
2
)}
%)`
,
},
{
name
:
'
Notifications
'
,
value
:
`
${
notificationsCount
}
(
${
parseFloat
(
notificationsCount
/
total
).
toFixed
(
2
)}
%)`
,
},
]}
/
>
<
/Col
>
<
/Row
>
<
/Grid
>
);
}
export
default
LogbookInvestigationStatisticsPanel
;
src/components/ManagerStats/GeneralStats/Logbook/LogbookStatisticsEvents.js
0 → 100644
View file @
b51c8e62
import
React
from
'
react
'
;
import
{
useResource
}
from
'
rest-hooks
'
;
import
{
Panel
}
from
'
react-bootstrap
'
;
import
CountlogbookStatisticsResource
from
'
../../../../resources/countLogbookStatistics
'
;
import
PlotWidget
from
'
../../../../containers/Stats/PlotWidget
'
;
function
LogbookStatisticsEvents
(
props
)
{
const
{
startDate
,
endDate
,
type
,
footer
}
=
props
;
/** Window with to resize the plots */
const
{
innerWidth
:
width
}
=
window
;
const
statisticsCount
=
useResource
(
CountlogbookStatisticsResource
.
listShape
(),
{
startDate
,
endDate
,
type
,
}
);
const
trace
=
{
x
:
statisticsCount
.
map
((
s
)
=>
s
.
_id
),
y
:
statisticsCount
.
map
((
s
)
=>
s
.
count
),
type
:
'
bar
'
,
};
return
(
<
div
className
=
"
app__inner
"
>
<
Panel
style
=
{{
margin
:
10
}}
bsStyle
=
"
primary
"
>
<
Panel
.
Heading
>
<
Panel
.
Title
componentClass
=
"
h3
"
>
{
type
}
created
by
date
<
/Panel.Title
>
<
/Panel.Heading
>
<
Panel
.
Body
>
<
PlotWidget
data
=
{[
trace
]}
layout
=
{{
width
:
width
*
0.8
}}
><
/PlotWidget
>
<
/Panel.Body
>
<
Panel
.
Footer
>
{
footer
}
<
/Panel.Footer
>
<
/Panel
>
<
/div
>
);
}
export
default
LogbookStatisticsEvents
;
src/components/ManagerStats/GeneralStats/Logbook/LogbookStatisticsTabs.js
0 → 100644
View file @
b51c8e62
import
React
from
'
react
'
;
import
{
useResource
}
from
'
rest-hooks
'
;
import
{
Tabs
,
Tab
}
from
'
react-bootstrap
'
;
import
LogbookStatistics
from
'
../../../../resources/logbookStatistics
'
;
import
LogbookUsagePanel
from
'
./LogbookUsagePanel
'
;
import
LogbookStatsResponsiveTable
from
'
./LogbookStatsResponsiveTable
'
;
import
LogbookStatisticsEvents
from
'
./LogbookStatisticsEvents
'
;
function
LogbookStatisticsTabs
(
props
)
{
const
{
startDate
,
endDate
}
=
props
;
const
statistics
=
useResource
(
LogbookStatistics
.
listShape
(),
{
startDate
,
endDate
,
});
return
(
<
Tabs
id
=
"
uncontrolled-tab-example
"
defaultActiveKey
=
{
1
}
>
<
Tab
eventKey
=
{
1
}
title
=
"
Logbook Usage
"
>
<
LogbookUsagePanel
startDate
=
{
startDate
}
endDate
=
{
endDate
}
statistics
=
{
statistics
}
><
/LogbookUsagePanel
>
<
/Tab
>
<
Tab
eventKey
=
{
2
}
title
=
"
Raw Statistics
"
>
<
LogbookStatsResponsiveTable
statistics
=
{
statistics
}
><
/LogbookStatsResponsiveTable
>
<
/Tab
>
<
Tab
eventKey
=
{
3
}
title
=
"
Events produced
"
>
<
LogbookStatisticsEvents
startDate
=
{
startDate
}
endDate
=
{
endDate
}
type
=
"
annotation
"
footer
=
"
Annotations are hand-made entries in the logbook done by users
"
><
/LogbookStatisticsEvents
>
<
LogbookStatisticsEvents
startDate
=
{
startDate
}
endDate
=
{
endDate
}
type
=
"
notification
"
footer
=
"
Notifications are entries produced and sent automatically by beamline software
"
><
/LogbookStatisticsEvents
>
<
/Tab
>
<
/Tabs
>
);
}
export
default
LogbookStatisticsTabs
;
src/components/ManagerStats/GeneralStats/Logbook/LogbookStatsResponsiveTable.js
0 → 100644
View file @
b51c8e62
import
React
from
'
react
'
;
import
{
stringifyBytesSize
}
from
'
../../../../helpers
'
;
import
{
dateFormatter
,
nameFormatter
}
from
'
../../../Investigation/utils
'
;
import
{
INVESTIGATION_DATE_FORMAT
}
from
'
../../../../constants
'
;
import
ResponsiveTable
from
'
../../../Table/ResponsiveTable
'
;
function
LogbookStatsResponsiveTable
(
props
)
{
const
{
statistics
}
=
props
;
return
(
<>
<
br
/>
<
ResponsiveTable
data
=
{
statistics
}
pageOptions
=
{{
showTotal
:
true
,
sizePerPageList
:
[
{
text
:
'
25
'
,
value
:
25
},
{
text
:
'
50
'
,
value
:
50
},
{
text
:
'
100
'
,
value
:
100
},
{
text
:
'
500
'
,
value
:
500
},
],
}}
columns
=
{[
{
text
:
'
investigationId
'
,
dataField
:
'
investigationId
'
,
hidden
:
true
,
},
{
text
:
'
Instrument
'
,
dataField
:
'
instrument
'
,
hidden
:
false
,
},
{
text
:
'
Proposal
'
,
dataField
:
'
name
'
,
hidden
:
false
,
formatter
:
(
_
,
record
)
=>
nameFormatter
(
{
id
:
record
.
investigationId
,
name
:
record
.
name
,
},
true
),
},
{
text
:
'
Title
'
,
dataField
:
'
title
'
,
hidden
:
false
,
},
{
text
:
'
Start
'
,
dataField
:
'
startDate
'
,
hidden
:
false
,
formatter
:
(
_
,
record
)
=>
dateFormatter
(
record
.
startDate
,
INVESTIGATION_DATE_FORMAT
,
false
),
},
{
text
:
'
End
'
,
dataField
:
'
endDate
'
,
hidden
:
false
,
formatter
:
(
_
,
record
)
=>
dateFormatter
(
record
.
endDate
,
INVESTIGATION_DATE_FORMAT
,
false
),
},
{
text
:
'
Annotations
'
,
dataField
:
'
annotations
'
,
hidden
:
false
,
sort
:
true
,
},
{
text
:
'
Notifications
'
,
dataField
:
'
notifications
'
,
hidden
:
false
,
sort
:
true
,
},
{
text
:
'
Total events
'
,
dataField
:
'
count
'
,
hidden
:
false
,
sort
:
true
,
},
{
text
:
'
Sample
'
,
dataField
:
'
__sampleCount
'
,
hidden
:
false
,
},
{
text
:
'
Files
'
,
dataField
:
'
__fileCount
'
,
hidden
:
false
,
},
{
text
:
'
Datasets
'
,
dataField
:
'
__datasetCount
'
,
hidden
:
false
,
},
{
text
:
'
Volume
'
,
dataField
:
'
__volume
'
,
hidden
:
false
,
formatter
:
(
_
,
record
)
=>
record
.
__volume
?
stringifyBytesSize
(
record
.
__volume
)
:
stringifyBytesSize
(
0
),
},
]}
/
>
<
/
>
);
}
export
default
LogbookStatsResponsiveTable
;
src/components/ManagerStats/GeneralStats/Logbook/LogbookUsagePanel.js
0 → 100644
View file @
b51c8e62
import
React
from
'
react
'
;
import
{
Alert
,
Panel
,
Grid
,
Row
,
Col
}
from
'
react-bootstrap
'
;
import
PlotWidget
from
'
../../../../containers/Stats/PlotWidget
'
;
import
LogbookInvestigationStatisticsPanel
from
'
./LogbookInvestigationStatisticsPanel
'
;
import
AnnotationsStatisticsPanel
from
'
./AnnotationsStatisticsPanel
'
;
const
getPlot
=
(
data
,
width
)
=>
{
return
(
<
PlotWidget
data
=
{
data
}
layout
=
{{
titlefont
:
{
size
:
16
,
},
width
,
height
:
300
,
barmode
:
'
group
'
,
font
:
{
family
:
'
Raleway, sans-serif
'
,
size
:
12
,
},
xaxis
:
{
tickangle
:
-
45
,
},
yaxis
:
{
title
:
'
Logbook Entries
'
,
tickangle
:
-
45
,
},
}}
responsive
=
{
true
}
><
/PlotWidget
>
);
};
function
LogbookUsagePanel
(
props
)
{
const
{
startDate
,
endDate
,
statistics
}
=
props
;
/** Window with to resize the plots */
const
{
innerWidth
:
width
}
=
window
;
/** Gets an array with the counts */
const
annotationsListCount
=
statistics
.
map
((
record
)
=>
record
.
annotations
?
record
.
annotations
:
0
);
const
notificationsListCount
=
statistics
.
map
((
record
)
=>
record
.
notifications
?
record
.
notifications
:
0
);
/** labels */
const
x
=
statistics
.
map
((
record
)
=>
`
${
record
.
name
}
${
record
.
instrument
}
`
);
const
annotationTrace
=
{
x
,
y
:
annotationsListCount
,
text
:
statistics
.
map
((
record
)
=>
`
${
record
.
instrument
}
`
),
textposition
:
'
auto
'
,
type
:
'
bar
'
,
name
:
'
Annotations
'
,
};
const
notificationsTrace
=
{
x
,
y
:
notificationsListCount
,
type
:
'
bar
'
,
name
:
'
Notifications
'
,
};
return
(
<
div
className
=
"
app__inner
"
>
<>
<
Alert
bsStyle
=
"
info
"
>
Logbook
Usage
for
period
<
strong
>
{
startDate
}
<
/strong> and{' '
}
<
strong
>
{
endDate
}
<
/strong>.<br /
>
Change
url
parameters
,
startDate
and
endDate
to
change
manually
the
range
of
dates
.
Example
:
/
manager
/
starts
/
logbook
?
startDate
=
2020
-
08
-
01
&
endDate
=
2020
-
09
-
01
<
/Alert
>
<
h1
>
<
/h1
>
<
Panel
style
=
{{
margin
:
10
}}
bsStyle
=
"
primary
"
>
<
Panel
.
Heading
>
<
Panel
.
Title
componentClass
=
"
h3
"
>
Number
of
entries
in
the
logbook
per
investigation
<
/Panel.Title
>
<
/Panel.Heading
>
<
Panel
.
Body
>
<
Grid
fluid
>
<
Row
>
<
Col
xs
=
{
12
}
md
=
{
8
}
>
{
getPlot
(
[
annotationTrace
,
notificationsTrace
],
width
*
0.6
,
`Number of entries in the logbook per investigation.`
)}
<
/Col
>
<
Col
xs
=
{
12
}
md
=
{
4
}
>
<
LogbookInvestigationStatisticsPanel
statistics
=
{
statistics
}
startDate
=
{
startDate
}
endDate
=
{
endDate
}
><
/LogbookInvestigationStatisticsPanel
>
<
/Col
>
<
/Row
>
<
/Grid
>
<
/Panel.Body
>
<
Panel
.
Footer
>
This
plot
shows
the
number
of
entries
in
the
logbook
for
each
investigation
.
It
can
give
a
hint
about
the
verbosity
(
number
of
logs
automatically
sent
)
of
each
beamline
.
<
/Panel.Footer
>
<
/Panel
>
<
Panel
style
=
{{
margin
:
10
}}
bsStyle
=
"
primary
"
>
<
Panel
.
Heading
>
<
Panel
.
Title
componentClass
=
"
h3
"
>
Annotations
(
hand
made
entries
)
per
investigation
<
/Panel.Title
>
<
/Panel.Heading
>
<
Panel
.
Body
>
<
Grid
fluid
>
<
Row
>
<
Col
xs
=
{
12
}
md
=
{
8
}
>
{
getPlot
([
annotationTrace
],
width
*
0.6
)}
<
/Col
>
<
Col
xs
=
{
12
}
md
=
{
4
}
>
<
AnnotationsStatisticsPanel
statistics
=
{
statistics
}
startDate
=
{
startDate
}
endDate
=
{
endDate
}
><
/AnnotationsStatisticsPanel
>
<
/Col
>
<
/Row
>
<
/Grid
>
<
/Panel.Body
>
<
/Panel
>
<
/
>
)
<
/div
>
);
}
export
default
LogbookUsagePanel
;
src/components/ManagerStats/GeneralStats/LogbookUsagePanel.js
deleted
100644 → 0
View file @
fabeb39a
import
React
,
{
useEffect
,
Suspense
,
useState
}
from
'
react
'
;
import
axios
from
'
axios
'
;
import
{
Alert
,
Panel
}
from
'
react-bootstrap
'
;
import
{
useSelector
}
from
'
react-redux
'
;
import
{
getStats
}
from
'
../../../api/icat-plus/logbook
'
;
import
Loader
from
'
../../Loader
'
;
import
ResponsiveTable
from
'
../../Table/ResponsiveTable
'
;
import
{
dateFormatter
}
from
'
../../Investigation/utils
'
;
import
{
INVESTIGATION_DATE_FORMAT
}
from
'
../../../constants
'
;
function
LogbookUsagePanel
(
props
)
{
const
{
startDate
,
endDate
}
=
props
;