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
OpenDAS
nni
Commits
c7187946
Commit
c7187946
authored
Feb 10, 2020
by
Lijiao
Committed by
GitHub
Feb 10, 2020
Browse files
Use office-fabric-ui components (#1964)
parent
fdfff50d
Changes
90
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1226 additions
and
1050 deletions
+1226
-1050
src/webui/src/components/overview/BasicInfo.tsx
src/webui/src/components/overview/BasicInfo.tsx
+23
-11
src/webui/src/components/overview/Details.tsx
src/webui/src/components/overview/Details.tsx
+36
-0
src/webui/src/components/overview/NumInput.tsx
src/webui/src/components/overview/NumInput.tsx
+15
-24
src/webui/src/components/overview/Progress.tsx
src/webui/src/components/overview/Progress.tsx
+188
-87
src/webui/src/components/overview/ProgressItem.tsx
src/webui/src/components/overview/ProgressItem.tsx
+16
-22
src/webui/src/components/overview/SearchSpace.tsx
src/webui/src/components/overview/SearchSpace.tsx
+0
-1
src/webui/src/components/overview/SuccessTable.tsx
src/webui/src/components/overview/SuccessTable.tsx
+110
-61
src/webui/src/components/overview/Title1.tsx
src/webui/src/components/overview/Title1.tsx
+6
-7
src/webui/src/components/overview/TrialProfile.tsx
src/webui/src/components/overview/TrialProfile.tsx
+0
-1
src/webui/src/components/public-child/DefaultMetric.tsx
src/webui/src/components/public-child/DefaultMetric.tsx
+0
-0
src/webui/src/components/public-child/LogPath.tsx
src/webui/src/components/public-child/LogPath.tsx
+0
-48
src/webui/src/components/public-child/MonacoEditor.tsx
src/webui/src/components/public-child/MonacoEditor.tsx
+30
-16
src/webui/src/components/public-child/OpenRow.tsx
src/webui/src/components/public-child/OpenRow.tsx
+96
-111
src/webui/src/components/public-child/PaiTrialChild.tsx
src/webui/src/components/public-child/PaiTrialChild.tsx
+2
-3
src/webui/src/components/public-child/PaiTrialLog.tsx
src/webui/src/components/public-child/PaiTrialLog.tsx
+6
-7
src/webui/src/components/trial-detail/DefaultMetricPoint.tsx
src/webui/src/components/trial-detail/DefaultMetricPoint.tsx
+93
-93
src/webui/src/components/trial-detail/Duration.tsx
src/webui/src/components/trial-detail/Duration.tsx
+86
-17
src/webui/src/components/trial-detail/Intermediate.tsx
src/webui/src/components/trial-detail/Intermediate.tsx
+32
-74
src/webui/src/components/trial-detail/Para.tsx
src/webui/src/components/trial-detail/Para.tsx
+90
-103
src/webui/src/components/trial-detail/TableList.tsx
src/webui/src/components/trial-detail/TableList.tsx
+397
-364
No files found.
src/webui/src/components/overview/BasicInfo.tsx
View file @
c7187946
import
{
Col
,
Row
,
Tooltip
}
from
'
antd
'
;
import
*
as
React
from
'
react
'
;
import
{
Stack
,
TooltipHost
,
getId
}
from
'
office-ui-fabric-react
'
;
import
{
EXPERIMENT
}
from
'
../../static/datamodel
'
;
import
{
formatTimestamp
}
from
'
../../static/function
'
;
...
...
@@ -8,36 +8,48 @@ interface BasicInfoProps {
}
class
BasicInfo
extends
React
.
Component
<
BasicInfoProps
,
{}
>
{
// Use getId() to ensure that the ID is unique on the page.
// (It's also okay to use a plain string without getId() and manually ensure uniqueness.)
// for tooltip user the log directory
private
_hostId
:
string
=
getId
(
'
tooltipHost
'
);
constructor
(
props
:
BasicInfoProps
)
{
super
(
props
);
}
render
():
React
.
ReactNode
{
return
(
<
Row
className
=
"main"
>
<
Col
span
=
{
8
}
className
=
"padItem basic"
>
<
Stack
horizontal
horizontalAlign
=
"space-between"
className
=
"main"
>
<
Stack
.
Item
grow
=
{
3
}
className
=
"padItem basic"
>
<
p
>
Name
</
p
>
<
div
>
{
EXPERIMENT
.
profile
.
params
.
experimentName
}
</
div
>
<
p
>
ID
</
p
>
<
div
>
{
EXPERIMENT
.
profile
.
id
}
</
div
>
</
Col
>
<
Col
span
=
{
8
}
className
=
"padItem basic"
>
</
Stack
.
Item
>
<
Stack
.
Item
grow
=
{
3
}
className
=
"padItem basic"
>
<
p
>
Start time
</
p
>
<
div
className
=
"nowrap"
>
{
formatTimestamp
(
EXPERIMENT
.
profile
.
startTime
)
}
</
div
>
<
p
>
End time
</
p
>
<
div
className
=
"nowrap"
>
{
formatTimestamp
(
EXPERIMENT
.
profile
.
endTime
)
}
</
div
>
</
Col
>
<
Col
span
=
{
8
}
className
=
"padItem basic"
>
</
Stack
.
Item
>
<
Stack
.
Item
className
=
"padItem basic"
>
<
p
>
Log directory
</
p
>
<
div
className
=
"nowrap"
>
<
Tooltip
placement
=
"top"
title
=
{
EXPERIMENT
.
profile
.
logDir
||
''
}
>
<
TooltipHost
// Tooltip message content
content
=
{
EXPERIMENT
.
profile
.
logDir
||
'
unknown
'
}
id
=
{
this
.
_hostId
}
calloutProps
=
{
{
gapSpace
:
0
}
}
styles
=
{
{
root
:
{
display
:
'
inline-block
'
}
}
}
>
{
/* show logDir */
}
{
EXPERIMENT
.
profile
.
logDir
||
'
unknown
'
}
</
Tooltip
>
</
Tooltip
Host
>
</
div
>
<
p
>
Training platform
</
p
>
<
div
className
=
"nowrap"
>
{
EXPERIMENT
.
profile
.
params
.
trainingServicePlatform
}
</
div
>
</
Col
>
</
Row
>
</
Stack
.
Item
>
</
Stack
>
);
}
}
...
...
src/webui/src/components/overview/Details.tsx
0 → 100644
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
{
DetailsRow
,
IDetailsRowBaseProps
}
from
'
office-ui-fabric-react
'
;
import
OpenRow
from
'
../public-child/OpenRow
'
;
interface
DetailsProps
{
detailsProps
:
IDetailsRowBaseProps
;
}
interface
DetailsState
{
isExpand
:
boolean
;
}
class
Details
extends
React
.
Component
<
DetailsProps
,
DetailsState
>
{
constructor
(
props
:
DetailsProps
)
{
super
(
props
);
this
.
state
=
{
isExpand
:
false
};
}
render
():
React
.
ReactNode
{
const
{
detailsProps
}
=
this
.
props
;
const
{
isExpand
}
=
this
.
state
;
return
(
<
div
>
<
div
onClick
=
{
():
void
=>
{
this
.
setState
(()
=>
({
isExpand
:
!
isExpand
}));
}
}
>
<
DetailsRow
{
...
detailsProps
}
/>
</
div
>
{
isExpand
&&
<
OpenRow
trialId
=
{
detailsProps
.
item
.
id
}
/>
}
</
div
>
);
}
}
export
default
Details
;
\ No newline at end of file
src/webui/src/components/overview/NumInput.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
{
Button
,
Row
}
from
'
antd
'
;
import
{
Stack
,
Primary
Button
}
from
'
office-ui-fabric-react
'
;
interface
ConcurrencyInputProps
{
value
:
number
;
...
...
@@ -36,47 +36,38 @@ class ConcurrencyInput extends React.Component<ConcurrencyInputProps, Concurrenc
render
():
React
.
ReactNode
{
if
(
this
.
state
.
editting
)
{
return
(
<
Row
className
=
"inputBox"
>
<
Stack
horizontal
className
=
"inputBox"
>
<
input
type
=
"number"
className
=
"concurrencyInput"
defaultValue
=
{
this
.
props
.
value
.
toString
()
}
ref
=
{
this
.
input
}
/>
<
Button
type
=
"primary"
className
=
"tableButton editStyle"
<
PrimaryButton
text
=
"Save"
onClick
=
{
this
.
save
}
>
Save
</
Button
>
<
Button
type
=
"primary"
onClick
=
{
this
.
cancel
}
/>
<
PrimaryButton
text
=
"Cancel"
style
=
{
{
display
:
'
inline-block
'
,
marginLeft
:
1
}
}
className
=
"tableButton editStyle"
>
Cancel
</
Button
>
</
Row
>
onClick
=
{
this
.
cancel
}
/>
</
Stack
>
);
}
else
{
return
(
<
Row
className
=
"inputBox"
>
<
Stack
horizontal
className
=
"inputBox"
>
<
input
type
=
"number"
className
=
"concurrencyInput"
disabled
=
{
true
}
value
=
{
this
.
props
.
value
}
/>
<
Button
type
=
"primary"
className
=
"tableButton editStyle"
<
PrimaryButton
text
=
"Edit"
onClick
=
{
this
.
edit
}
>
Edit
</
Button
>
</
Row
>
/>
</
Stack
>
);
}
}
...
...
src/webui/src/components/overview/Progress.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
{
Row
,
Col
,
Popover
,
message
}
from
'
antd
'
;
import
{
Stack
,
Callout
,
Link
,
IconButton
,
FontWeights
,
mergeStyleSets
,
getId
,
getTheme
,
StackItem
}
from
'
office-ui-fabric-react
'
;
import
axios
from
'
axios
'
;
import
{
MANAGER_IP
}
from
'
../../static/const
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
convertTime
}
from
'
../../static/function
'
;
import
ConcurrencyInput
from
'
./NumInput
'
;
import
ProgressBar
from
'
./ProgressItem
'
;
import
LogDrawer
from
'
../Modal/LogDrawer
'
;
import
LogDrawer
from
'
../Modals/LogDrawer
'
;
import
MessageInfo
from
'
../Modals/MessageInfo
'
;
import
'
../../static/style/progress.scss
'
;
import
'
../../static/style/probar.scss
'
;
interface
ProgressProps
{
concurrency
:
number
;
bestAccuracy
:
number
;
...
...
@@ -19,24 +19,106 @@ interface ProgressProps {
interface
ProgressState
{
isShowLogDrawer
:
boolean
;
isCalloutVisible
?:
boolean
;
isShowSucceedInfo
:
boolean
;
info
:
string
;
typeInfo
:
string
;
}
const
itemStyles
:
React
.
CSSProperties
=
{
height
:
50
,
width
:
100
};
const
theme
=
getTheme
();
const
styles
=
mergeStyleSets
({
buttonArea
:
{
verticalAlign
:
'
top
'
,
display
:
'
inline-block
'
,
textAlign
:
'
center
'
,
// margin: '0 100px',
minWidth
:
30
,
height
:
30
},
callout
:
{
maxWidth
:
300
},
header
:
{
padding
:
'
18px 24px 12px
'
},
title
:
[
theme
.
fonts
.
xLarge
,
{
margin
:
0
,
color
:
theme
.
palette
.
neutralPrimary
,
fontWeight
:
FontWeights
.
semilight
}
],
inner
:
{
height
:
'
100%
'
,
padding
:
'
0 24px 20px
'
},
actions
:
{
position
:
'
relative
'
,
marginTop
:
20
,
width
:
'
100%
'
,
whiteSpace
:
'
nowrap
'
},
subtext
:
[
theme
.
fonts
.
small
,
{
margin
:
0
,
color
:
theme
.
palette
.
neutralPrimary
,
fontWeight
:
FontWeights
.
semilight
}
],
link
:
[
theme
.
fonts
.
medium
,
{
color
:
theme
.
palette
.
neutralPrimary
}
]
});
class
Progressed
extends
React
.
Component
<
ProgressProps
,
ProgressState
>
{
private
menuButtonElement
!
:
HTMLDivElement
|
null
;
private
labelId
:
string
=
getId
(
'
callout-label
'
);
private
descriptionId
:
string
=
getId
(
'
callout-description
'
);
constructor
(
props
:
ProgressProps
)
{
super
(
props
);
this
.
state
=
{
isShowLogDrawer
:
false
isShowLogDrawer
:
false
,
isCalloutVisible
:
false
,
isShowSucceedInfo
:
false
,
info
:
''
,
typeInfo
:
'
success
'
};
}
hideSucceedInfo
=
():
void
=>
{
this
.
setState
(()
=>
({
isShowSucceedInfo
:
false
}));
}
/**
* info: message content
* typeInfo: message type: success | error...
* continuousTime: show time, 2000ms
*/
showMessageInfo
=
(
info
:
string
,
typeInfo
:
string
):
void
=>
{
this
.
setState
(()
=>
({
info
,
typeInfo
,
isShowSucceedInfo
:
true
}));
setTimeout
(
this
.
hideSucceedInfo
,
2000
);
}
editTrialConcurrency
=
async
(
userInput
:
string
):
Promise
<
void
>
=>
{
if
(
!
userInput
.
match
(
/^
[
1-9
]\d
*$/
))
{
message
.
error
(
'
Please enter a positive integer!
'
,
2
);
this
.
showMessageInfo
(
'
Please enter a positive integer!
'
,
'
error
'
);
return
;
}
const
newConcurrency
=
parseInt
(
userInput
,
10
);
if
(
newConcurrency
===
this
.
props
.
concurrency
)
{
m
essage
.
i
nfo
(
`
Trial concurrency has not changed
`
,
2
);
this
.
showM
essage
I
nfo
(
'
Trial concurrency has not changed
'
,
'
error
'
);
return
;
}
...
...
@@ -50,19 +132,19 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
params
:
{
update_type
:
'
TRIAL_CONCURRENCY
'
}
});
if
(
res
.
status
===
200
)
{
message
.
success
(
`
Successfully updated trial concurrency
`
);
this
.
showMessageInfo
(
'
Successfully updated trial concurrency
'
,
'
success
'
);
// NOTE: should we do this earlier in favor of poor networks?
this
.
props
.
changeConcurrency
(
newConcurrency
);
}
}
catch
(
error
)
{
if
(
error
.
response
&&
error
.
response
.
data
.
error
)
{
message
.
error
(
`Failed to update trial concurrency\n
${
error
.
response
.
data
.
error
}
`
);
this
.
showMessageInfo
(
`Failed to update trial concurrency\n
${
error
.
response
.
data
.
error
}
`
,
'
error
'
);
}
else
if
(
error
.
response
)
{
message
.
error
(
`Failed to update trial concurrency\nServer responsed
${
error
.
response
.
status
}
`
);
this
.
showMessageInfo
(
`Failed to update trial concurrency\nServer responsed
${
error
.
response
.
status
}
`
,
'
error
'
);
}
else
if
(
error
.
message
)
{
message
.
error
(
`Failed to update trial concurrency\n
${
error
.
message
}
`
);
this
.
showMessageInfo
(
`Failed to update trial concurrency\n
${
error
.
message
}
`
,
'
error
'
);
}
else
{
message
.
error
(
`Failed to update trial concurrency\nUnknown error`
);
this
.
showMessageInfo
(
`Failed to update trial concurrency\nUnknown error`
,
'
error
'
);
}
}
}
...
...
@@ -75,55 +157,79 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
this
.
setState
({
isShowLogDrawer
:
false
});
}
onDismiss
=
():
void
=>
{
this
.
setState
({
isCalloutVisible
:
false
});
}
onShow
=
():
void
=>
{
this
.
setState
({
isCalloutVisible
:
true
});
}
render
():
React
.
ReactNode
{
const
{
bestAccuracy
}
=
this
.
props
;
const
{
isShowLogDrawer
}
=
this
.
state
;
const
{
isShowLogDrawer
,
isCalloutVisible
,
isShowSucceedInfo
,
info
,
typeInfo
}
=
this
.
state
;
const
count
=
TRIALS
.
countStatus
();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const
stoppedCount
=
count
.
get
(
'
USER_CANCELED
'
)
!
+
count
.
get
(
'
SYS_CANCELED
'
)
!
+
count
.
get
(
'
EARLY_STOPPED
'
)
!
;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const
bar2
=
count
.
get
(
'
RUNNING
'
)
!
+
count
.
get
(
'
SUCCEEDED
'
)
!
+
count
.
get
(
'
FAILED
'
)
!
+
stoppedCount
;
const
bar2Percent
=
(
bar2
/
EXPERIMENT
.
profile
.
params
.
maxTrialNum
)
*
100
;
const
percent
=
(
EXPERIMENT
.
profile
.
execDuration
/
EXPERIMENT
.
profile
.
params
.
maxExecDuration
)
*
100
;
// support type [0, 1], not 98%
const
bar2Percent
=
bar2
/
EXPERIMENT
.
profile
.
params
.
maxTrialNum
;
const
percent
=
EXPERIMENT
.
profile
.
execDuration
/
EXPERIMENT
.
profile
.
params
.
maxExecDuration
;
const
remaining
=
convertTime
(
EXPERIMENT
.
profile
.
params
.
maxExecDuration
-
EXPERIMENT
.
profile
.
execDuration
);
const
maxDuration
=
convertTime
(
EXPERIMENT
.
profile
.
params
.
maxExecDuration
);
const
maxTrialNum
=
EXPERIMENT
.
profile
.
params
.
maxTrialNum
;
const
execDuration
=
convertTime
(
EXPERIMENT
.
profile
.
execDuration
);
let
errorContent
;
if
(
EXPERIMENT
.
error
)
{
errorContent
=
(
<
div
className
=
"errors"
>
{
EXPERIMENT
.
error
}
<
div
><
a
href
=
"#"
onClick
=
{
this
.
isShowDrawer
}
>
Learn about
</
a
></
div
>
</
div
>
);
}
return
(
<
Row
className
=
"progress"
id
=
"barBack"
>
<
Row
className
=
"basic lineBasic"
>
<
Stack
className
=
"progress"
id
=
"barBack"
>
<
Stack
className
=
"basic lineBasic"
>
<
p
>
Status
</
p
>
<
div
className
=
"status"
>
<
span
className
=
{
EXPERIMENT
.
status
}
>
{
EXPERIMENT
.
status
}
</
span
>
<
Stack
horizontal
className
=
"status"
>
<
span
className
=
{
`
${
EXPERIMENT
.
status
}
status-text`
}
>
{
EXPERIMENT
.
status
}
</
span
>
{
EXPERIMENT
.
status
===
'
ERROR
'
?
<
Popover
placement
=
"rightTop"
content
=
{
errorContent
}
title
=
"Error"
trigger
=
"hover"
>
<
span
className
=
"errorBtn"
>
i
</
span
>
</
Popover
>
<
div
>
<
div
className
=
{
styles
.
buttonArea
}
ref
=
{
(
val
):
any
=>
this
.
menuButtonElement
=
val
}
>
<
IconButton
iconProps
=
{
{
iconName
:
'
info
'
}
}
onClick
=
{
isCalloutVisible
?
this
.
onDismiss
:
this
.
onShow
}
/>
</
div
>
{
isCalloutVisible
&&
(
<
Callout
className
=
{
styles
.
callout
}
ariaLabelledBy
=
{
this
.
labelId
}
ariaDescribedBy
=
{
this
.
descriptionId
}
role
=
"alertdialog"
gapSpace
=
{
0
}
target
=
{
this
.
menuButtonElement
}
onDismiss
=
{
this
.
onDismiss
}
setInitialFocus
=
{
true
}
>
<
div
className
=
{
styles
.
header
}
>
<
p
className
=
{
styles
.
title
}
id
=
{
this
.
labelId
}
>
Error
</
p
>
</
div
>
<
div
className
=
{
styles
.
inner
}
>
<
p
className
=
{
styles
.
subtext
}
id
=
{
this
.
descriptionId
}
>
{
EXPERIMENT
.
error
}
</
p
>
<
div
className
=
{
styles
.
actions
}
>
<
Link
className
=
{
styles
.
link
}
onClick
=
{
this
.
isShowDrawer
}
>
Learn about
</
Link
>
</
div
>
</
div
>
</
Callout
>
)
}
</
div
>
:
<
span
/>
null
}
</
div
>
</
Row
>
</
Stack
>
</
Stack
>
<
ProgressBar
who
=
"Duration"
percent
=
{
percent
}
...
...
@@ -138,55 +244,49 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
bgclass
=
{
EXPERIMENT
.
status
}
maxString
=
{
`Max trial number:
${
maxTrialNum
}
`
}
/>
<
Row
className
=
"basic colorOfbasic mess"
>
<
p
>
Best metric
</
p
>
<
div
>
{
isNaN
(
bestAccuracy
)
?
'
N/A
'
:
bestAccuracy
.
toFixed
(
6
)
}
</
div
>
</
Row
>
<
Row
className
=
"mess"
>
<
Col
span
=
{
6
}
>
<
Row
className
=
"basic colorOfbasic"
>
<
p
>
Spent
</
p
>
<
div
>
{
execDuration
}
</
div
>
</
Row
>
</
Col
>
<
Col
span
=
{
6
}
>
<
Row
className
=
"basic colorOfbasic"
>
<
p
>
Remaining
</
p
>
<
div
className
=
"time"
>
{
remaining
}
</
div
>
</
Row
>
</
Col
>
<
Col
span
=
{
12
}
>
<
Stack
className
=
"basic colorOfbasic mess"
horizontal
>
<
StackItem
grow
=
{
50
}
>
<
p
>
Best metric
</
p
>
<
div
>
{
isNaN
(
bestAccuracy
)
?
'
N/A
'
:
bestAccuracy
.
toFixed
(
6
)
}
</
div
>
</
StackItem
>
<
StackItem
>
{
isShowSucceedInfo
&&
<
MessageInfo
className
=
"info"
typeInfo
=
{
typeInfo
}
info
=
{
info
}
/>
}
</
StackItem
>
</
Stack
>
<
Stack
horizontal
horizontalAlign
=
"space-between"
className
=
"mess"
>
<
span
style
=
{
itemStyles
}
className
=
"basic colorOfbasic"
>
<
p
>
Spent
</
p
>
<
div
>
{
execDuration
}
</
div
>
</
span
>
<
span
style
=
{
itemStyles
}
className
=
"basic colorOfbasic"
>
<
p
>
Remaining
</
p
>
<
div
className
=
"time"
>
{
remaining
}
</
div
>
</
span
>
<
span
style
=
{
itemStyles
}
>
{
/* modify concurrency */
}
<
p
>
Concurrency
</
p
>
<
ConcurrencyInput
value
=
{
this
.
props
.
concurrency
}
updateValue
=
{
this
.
editTrialConcurrency
}
/>
</
Col
>
</
Row
>
<
Row
className
=
"mess"
>
<
Col
span
=
{
6
}
>
<
Row
className
=
"basic colorOfbasic"
>
<
p
>
Running
</
p
>
<
div
>
{
count
.
get
(
'
RUNNING
'
)
}
</
div
>
</
Row
>
</
Col
>
<
Col
span
=
{
6
}
>
<
Row
className
=
"basic colorOfbasic"
>
<
p
>
Succeeded
</
p
>
<
div
>
{
count
.
get
(
'
SUCCEEDED
'
)
}
</
div
>
</
Row
>
</
Col
>
<
Col
span
=
{
6
}
>
<
Row
className
=
"basic"
>
<
p
>
Stopped
</
p
>
<
div
>
{
stoppedCount
}
</
div
>
</
Row
>
</
Col
>
<
Col
span
=
{
6
}
>
<
Row
className
=
"basic"
>
<
p
>
Failed
</
p
>
<
div
>
{
count
.
get
(
'
FAILED
'
)
}
</
div
>
</
Row
>
</
Col
>
</
Row
>
</
span
>
<
span
style
=
{
itemStyles
}
className
=
"basic colorOfbasic"
></
span
>
</
Stack
>
<
Stack
horizontal
horizontalAlign
=
"space-between"
className
=
"mess"
>
<
div
style
=
{
itemStyles
}
className
=
"basic colorOfbasic"
>
<
p
>
Running
</
p
>
<
div
>
{
count
.
get
(
'
RUNNING
'
)
}
</
div
>
</
div
>
<
div
style
=
{
itemStyles
}
className
=
"basic colorOfbasic"
>
<
p
>
Succeeded
</
p
>
<
div
>
{
count
.
get
(
'
SUCCEEDED
'
)
}
</
div
>
</
div
>
<
div
style
=
{
itemStyles
}
className
=
"basic"
>
<
p
>
Stopped
</
p
>
<
div
>
{
stoppedCount
}
</
div
>
</
div
>
<
div
style
=
{
itemStyles
}
className
=
"basic"
>
<
p
>
Failed
</
p
>
<
div
>
{
count
.
get
(
'
FAILED
'
)
}
</
div
>
</
div
>
</
Stack
>
{
/* learn about click -> default active key is dispatcher. */
}
{
isShowLogDrawer
?
(
<
LogDrawer
...
...
@@ -194,9 +294,10 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
activeTab
=
"dispatcher"
/>
)
:
null
}
</
Row
>
</
Stack
>
);
}
}
export
default
Progressed
;
src/webui/src/components/overview/ProgressItem.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
{
Row
,
Col
,
Progress
}
from
'
antd
'
;
import
{
Stack
,
StackItem
,
ProgressIndicator
}
from
'
office-ui-fabric-react
'
;
interface
ProItemProps
{
who
:
string
;
...
...
@@ -18,29 +18,23 @@ class ProgressBar extends React.Component<ProItemProps, {}> {
render
():
React
.
ReactNode
{
const
{
who
,
percent
,
description
,
maxString
,
bgclass
}
=
this
.
props
;
return
(
<
div
>
<
Row
className
=
{
`probar
${
bgclass
}
`
}
>
<
Col
span
=
{
8
}
>
<
div
className
=
"name"
>
{
who
}
</
div
>
</
Col
>
<
Col
span
=
{
16
}
className
=
"bar"
>
<
div
className
=
"showProgress"
>
<
Progress
percent
=
{
percent
}
strokeWidth
=
{
30
}
// strokeLinecap={'square'}
format
=
{
():
string
=>
description
}
/>
</
div
>
<
Row
className
=
"description"
>
<
Col
span
=
{
9
}
>
0
</
Col
>
<
Col
className
=
"right"
span
=
{
15
}
>
{
maxString
}
</
Col
>
</
Row
>
</
Col
>
</
Row
>
<
br
/>
<
Stack
horizontal
className
=
{
`probar
${
bgclass
}
`
}
>
<
div
className
=
"name"
>
{
who
}
</
div
>
<
div
className
=
"showProgress"
style
=
{
{
width
:
'
80%
'
}
}
>
<
ProgressIndicator
barHeight
=
{
30
}
percentComplete
=
{
percent
}
/>
<
Stack
horizontal
className
=
"boundary"
>
<
StackItem
grow
=
{
30
}
>
0
</
StackItem
>
<
StackItem
className
=
"right"
grow
=
{
70
}
>
{
maxString
}
</
StackItem
>
</
Stack
>
</
div
>
<
div
className
=
"description"
style
=
{
{
width
:
'
20%
'
}
}
>
{
description
}
</
div
>
</
Stack
>
<
br
/>
</
div
>
);
}
...
...
src/webui/src/components/overview/SearchSpace.tsx
View file @
c7187946
...
...
@@ -18,7 +18,6 @@ class SearchSpace extends React.Component<SearchspaceProps, {}> {
return
(
<
div
className
=
"searchSpace"
>
<
MonacoEditor
width
=
"100%"
height
=
"361"
language
=
"json"
theme
=
"vs-light"
...
...
src/webui/src/components/overview/SuccessTable.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
{
Table
}
from
'
antd
'
;
import
OpenRow
from
'
../public-child/OpenRow
'
;
import
DefaultMetric
from
'
../public-child/DefaultMetrc
'
;
import
{
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
TableRecord
}
from
'
../../static/interface
'
;
import
{
DetailsList
,
IDetailsListProps
,
IColumn
}
from
'
office-ui-fabric-react
'
;
import
DefaultMetric
from
'
../public-child/DefaultMetric
'
;
import
Details
from
'
./Details
'
;
import
{
convertDuration
}
from
'
../../static/function
'
;
import
'
../../static/style/tableStatus.css
'
;
import
{
TRIALS
}
from
'
../../static/datamodel
'
;
import
'
../../static/style/succTable.scss
'
;
import
'
../../static/style/openRow.scss
'
;
interface
SuccessTableProps
{
trialIds
:
string
[];
}
function
openRow
(
record
:
TableRecord
):
any
{
return
(
<
OpenRow
trialId
=
{
record
.
id
}
/>
);
interface
SuccessTableState
{
columns
:
IColumn
[];
source
:
Array
<
any
>
;
}
class
SuccessTable
extends
React
.
Component
<
SuccessTableProps
,
{}
>
{
class
SuccessTable
extends
React
.
Component
<
SuccessTableProps
,
SuccessTableState
>
{
constructor
(
props
:
SuccessTableProps
)
{
super
(
props
);
this
.
state
=
{
columns
:
this
.
columns
,
source
:
TRIALS
.
table
(
this
.
props
.
trialIds
)
};
}
render
():
React
.
ReactNode
{
const
columns
=
[
{
title
:
'
Trial No.
'
,
dataIndex
:
'
sequenceId
'
,
className
:
'
tableHead
'
},
{
title
:
'
ID
'
,
dataIndex
:
'
id
'
,
width
:
80
,
className
:
'
tableHead leftTitle
'
,
render
:
(
text
:
string
,
record
:
TableRecord
):
React
.
ReactNode
=>
{
return
(
<
div
>
{
record
.
id
}
</
div
>
);
},
},
{
title
:
'
Duration
'
,
dataIndex
:
'
duration
'
,
width
:
140
,
render
:
(
text
:
string
,
record
:
TableRecord
):
React
.
ReactNode
=>
{
return
(
<
div
className
=
"durationsty"
><
div
>
{
convertDuration
(
record
.
duration
)
}
</
div
></
div
>
);
},
},
{
title
:
'
Status
'
,
dataIndex
:
'
status
'
,
width
:
150
,
className
:
'
tableStatus
'
,
render
:
(
text
:
string
,
record
:
TableRecord
):
React
.
ReactNode
=>
{
return
(
<
div
className
=
{
`
${
record
.
status
}
commonStyle`
}
>
{
record
.
status
}
</
div
>
);
}
},
{
title
:
'
Default metric
'
,
dataIndex
:
'
accuracy
'
,
render
:
(
text
:
string
,
record
:
TableRecord
):
React
.
ReactNode
=>
{
return
(
<
DefaultMetric
trialId
=
{
record
.
id
}
/>
);
}
private
onRenderRow
:
IDetailsListProps
[
'
onRenderRow
'
]
=
props
=>
{
if
(
props
)
{
return
<
Details
detailsProps
=
{
props
}
/>;
}
return
null
;
};
onColumnClick
=
(
ev
:
React
.
MouseEvent
<
HTMLElement
>
,
getColumn
:
IColumn
):
void
=>
{
const
{
columns
,
source
}
=
this
.
state
;
const
newColumns
:
IColumn
[]
=
columns
.
slice
();
const
currColumn
:
IColumn
=
newColumns
.
filter
(
item
=>
getColumn
.
key
===
item
.
key
)[
0
];
newColumns
.
forEach
((
newCol
:
IColumn
)
=>
{
if
(
newCol
===
currColumn
)
{
currColumn
.
isSortedDescending
=
!
currColumn
.
isSortedDescending
;
currColumn
.
isSorted
=
true
;
}
else
{
newCol
.
isSorted
=
false
;
newCol
.
isSortedDescending
=
true
;
}
];
});
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const
newItems
=
this
.
copyAndSort
(
source
,
currColumn
.
fieldName
!
,
currColumn
.
isSortedDescending
);
this
.
setState
({
columns
:
newColumns
,
source
:
newItems
});
};
private
copyAndSort
<
T
>
(
items
:
T
[],
columnKey
:
string
,
isSortedDescending
?:
boolean
):
T
[]
{
const
key
=
columnKey
as
keyof
T
;
return
items
.
slice
(
0
).
sort
((
a
:
T
,
b
:
T
)
=>
((
isSortedDescending
?
a
[
key
]
<
b
[
key
]
:
a
[
key
]
>
b
[
key
])
?
1
:
-
1
));
}
columns
=
[
{
name
:
'
Trial No.
'
,
key
:
'
sequenceId
'
,
fieldName
:
'
sequenceId
'
,
// required!
minWidth
:
60
,
maxWidth
:
80
,
data
:
'
number
'
,
onColumnClick
:
this
.
onColumnClick
},
{
name
:
'
ID
'
,
key
:
'
id
'
,
fieldName
:
'
id
'
,
minWidth
:
80
,
maxWidth
:
150
,
className
:
'
tableHead leftTitle
'
,
data
:
'
string
'
,
onColumnClick
:
this
.
onColumnClick
},
{
name
:
'
Duration
'
,
key
:
'
duration
'
,
minWidth
:
100
,
maxWidth
:
150
,
fieldName
:
'
duration
'
,
data
:
'
number
'
,
onColumnClick
:
this
.
onColumnClick
,
onRender
:
(
item
:
any
):
React
.
ReactNode
=>
{
return
(
<
div
className
=
"durationsty"
><
div
>
{
convertDuration
(
item
.
duration
)
}
</
div
></
div
>
);
},
},
{
name
:
'
Status
'
,
key
:
'
status
'
,
minWidth
:
100
,
maxWidth
:
150
,
fieldName
:
'
status
'
,
onRender
:
(
item
:
any
):
React
.
ReactNode
=>
{
return
(
<
div
className
=
{
`
${
item
.
status
}
commonStyle`
}
>
{
item
.
status
}
</
div
>
);
}
},
{
name
:
'
Default metric
'
,
key
:
'
accuracy
'
,
fieldName
:
'
accuracy
'
,
minWidth
:
100
,
maxWidth
:
150
,
data
:
'
number
'
,
onColumnClick
:
this
.
onColumnClick
,
onRender
:
(
item
:
any
):
React
.
ReactNode
=>
{
return
(
<
DefaultMetric
trialId
=
{
item
.
id
}
/>
);
}
}
];
render
():
React
.
ReactNode
{
const
{
columns
,
source
}
=
this
.
state
;
return
(
<
div
className
=
"tabScroll"
>
<
Table
<
div
id
=
"succTable"
>
{
/* TODO: [style] lineHeight question */
}
<
DetailsList
columns
=
{
columns
}
expandedRowRender
=
{
openRow
}
dataSource
=
{
TRIALS
.
table
(
this
.
props
.
trialIds
)
}
className
=
"commonTableStyle"
pagination
=
{
false
}
items
=
{
source
}
setKey
=
"set"
compact
=
{
true
}
onRenderRow
=
{
this
.
onRenderRow
}
selectionMode
=
{
0
}
// close selector function
/>
</
div
>
);
...
...
src/webui/src/components/overview/Title1.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
{
Stack
}
from
'
office-ui-fabric-react
'
;
import
'
../../static/style/overviewTitle.scss
'
;
interface
Title1Props
{
text
:
string
;
icon
?:
string
;
...
...
@@ -15,12 +16,10 @@ class Title1 extends React.Component<Title1Props, {}> {
render
():
React
.
ReactNode
{
const
{
text
,
icon
,
bgcolor
}
=
this
.
props
;
return
(
<
div
>
<
div
className
=
"panelTitle"
style
=
{
{
backgroundColor
:
bgcolor
}
}
>
<
img
src
=
{
require
(
`../../static/img/icon/
${
icon
}
`
)
}
alt
=
"icon"
/>
<
span
>
{
text
}
</
span
>
</
div
>
</
div
>
<
Stack
horizontal
className
=
"panelTitle"
style
=
{
{
backgroundColor
:
bgcolor
}
}
>
<
img
src
=
{
require
(
`../../static/img/icon/
${
icon
}
`
)
}
alt
=
"icon"
/>
<
span
>
{
text
}
</
span
>
</
Stack
>
);
}
}
...
...
src/webui/src/components/overview/TrialProfile.tsx
View file @
c7187946
...
...
@@ -27,7 +27,6 @@ class TrialInfo extends React.Component<TrialInfoProps, {}> {
};
const
profile
=
JSON
.
stringify
(
EXPERIMENT
.
profile
,
filter
,
2
);
// FIXME: highlight not working?
return
(
<
div
className
=
"profile"
>
<
MonacoEditor
...
...
src/webui/src/components/public-child/DefaultMetrc.tsx
→
src/webui/src/components/public-child/DefaultMetr
i
c.tsx
View file @
c7187946
File moved
src/webui/src/components/public-child/LogPath.tsx
deleted
100644 → 0
View file @
fdfff50d
import
*
as
React
from
'
react
'
;
import
LogPathChild
from
'
./LogPathChild
'
;
interface
LogpathProps
{
logStr
:
string
;
}
class
LogPath
extends
React
.
Component
<
LogpathProps
,
{}
>
{
constructor
(
props
:
LogpathProps
)
{
super
(
props
);
}
render
():
React
.
ReactNode
{
const
{
logStr
}
=
this
.
props
;
const
isTwopath
=
logStr
.
indexOf
(
'
,
'
)
!==
-
1
?
true
:
false
;
return
(
<
div
>
{
isTwopath
?
<
div
>
<
LogPathChild
eachLogpath
=
{
logStr
.
split
(
'
,
'
)[
0
]
}
logName
=
"LogPath:"
/>
<
LogPathChild
eachLogpath
=
{
logStr
.
split
(
'
,
'
)[
1
]
}
logName
=
"Log on HDFS:"
/>
</
div
>
:
<
LogPathChild
eachLogpath
=
{
logStr
}
logName
=
"Log path:"
/>
}
</
div
>
);
}
}
export
default
LogPath
;
\ No newline at end of file
src/webui/src/components/public-child/MonacoEditor.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
{
Spin
}
from
'
antd
'
;
import
{
Spin
ner
}
from
'
office-ui-fabric-react
'
;
import
{
DRAWEROPTION
}
from
'
../../static/const
'
;
import
MonacoEditor
from
'
react-monaco-editor
'
;
...
...
@@ -11,7 +11,7 @@ interface MonacoEditorProps {
class
MonacoHTML
extends
React
.
Component
<
MonacoEditorProps
,
{}
>
{
public
_isMonacoMount
:
boolean
;
public
_isMonacoMount
!
:
boolean
;
constructor
(
props
:
MonacoEditorProps
)
{
super
(
props
);
...
...
@@ -25,23 +25,37 @@ class MonacoHTML extends React.Component<MonacoEditorProps, {}> {
this
.
_isMonacoMount
=
false
;
}
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
content
,
loading
,
height
}
=
this
.
props
;
return
(
<
div
className
=
"just-for-log"
>
<
Spin
// tip="Loading..."
style
=
{
{
width
:
'
100%
'
,
height
:
height
}
}
spinning
=
{
loading
}
>
<
MonacoEditor
width
=
"100%"
height
=
{
height
}
language
=
"json"
value
=
{
content
}
options
=
{
DRAWEROPTION
}
/>
</
Spin
>
{
loading
?
<
Spinner
label
=
"Wait, wait..."
ariaLive
=
"assertive"
labelPosition
=
"right"
styles
=
{
{
root
:
{
width
:
'
100%
'
,
height
:
height
}
}
}
>
<
MonacoEditor
width
=
"100%"
height
=
{
height
}
language
=
"json"
value
=
{
content
}
options
=
{
DRAWEROPTION
}
/>
</
Spinner
>
:
<
MonacoEditor
width
=
"100%"
height
=
{
height
}
language
=
"json"
value
=
{
content
}
options
=
{
DRAWEROPTION
}
/>
}
</
div
>
);
}
...
...
src/webui/src/components/public-child/OpenRow.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
*
as
copy
from
'
copy-to-clipboard
'
;
import
PaiTrialLog
from
'
../public-child/PaiTrialLog
'
;
import
TrialLog
from
'
../public-child/TrialLog
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
Stack
,
PrimaryButton
,
Pivot
,
PivotItem
}
from
'
office-ui-fabric-react
'
;
import
{
Trial
}
from
'
../../static/model/trial
'
;
import
{
Row
,
Tabs
,
Button
,
message
,
Modal
}
from
'
antd
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
MANAGER_IP
}
from
'
../../static/const
'
;
import
JSONTree
from
'
react-json-tree
'
;
import
PaiTrialLog
from
'
../public-child/PaiTrialLog
'
;
import
TrialLog
from
'
../public-child/TrialLog
'
;
import
MessageInfo
from
'
../Modals/MessageInfo
'
;
import
'
../../static/style/overview.scss
'
;
import
'
../../static/style/copyParameter.scss
'
;
import
JSONTree
from
'
react-json-tree
'
;
const
TabPane
=
Tabs
.
TabPane
;
interface
OpenRowProps
{
trialId
:
string
;
}
interface
OpenRowState
{
isShowFormatModal
:
boolean
;
formatStr
:
string
;
typeInfo
:
string
;
info
:
string
;
isHidenInfo
:
boolean
;
}
class
OpenRow
extends
React
.
Component
<
OpenRowProps
,
OpenRowState
>
{
...
...
@@ -25,127 +26,111 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
constructor
(
props
:
OpenRowProps
)
{
super
(
props
);
this
.
state
=
{
isShowFormatModal
:
false
,
formatStr
:
''
typeInfo
:
''
,
info
:
''
,
isHidenInfo
:
true
};
}
showFormatModal
=
(
trial
:
Trial
):
void
=>
{
// get copy parameters
const
params
=
JSON
.
stringify
(
trial
.
info
.
hyperParameters
,
null
,
4
);
// open modal with format string
this
.
setState
({
isShowFormatModal
:
true
,
formatStr
:
params
});
hideMessageInfo
=
():
void
=>
{
this
.
setState
(()
=>
({
isHidenInfo
:
true
}));
}
hideFormatModal
=
():
void
=>
{
// close modal, destroy state format string data
this
.
setState
({
isShowFormatModal
:
false
,
formatStr
:
''
});
/**
* info: message content
* typeInfo: message type: success | error...
* continuousTime: show time, 2000ms
*/
getCopyStatus
=
(
info
:
string
,
typeInfo
:
string
):
void
=>
{
this
.
setState
(()
=>
({
info
,
typeInfo
,
isHidenInfo
:
false
}));
setTimeout
(
this
.
hideMessageInfo
,
2000
);
}
copyParams
=
():
void
=>
{
// json format
const
{
formatStr
}
=
this
.
state
;
if
(
copy
(
formatStr
))
{
message
.
destroy
();
message
.
success
(
'
Success copy parameters to clipboard in form of python dict !
'
,
3
);
copyParams
=
(
trial
:
Trial
):
void
=>
{
// get copy parameters
const
params
=
JSON
.
stringify
(
trial
.
description
.
parameters
,
null
,
4
);
if
(
copy
.
default
(
params
))
{
this
.
getCopyStatus
(
'
Success copy parameters to clipboard in form of python dict !
'
,
'
success
'
);
}
else
{
message
.
destroy
();
message
.
error
(
'
Failed !
'
,
2
);
this
.
getCopyStatus
(
'
Failed !
'
,
'
error
'
);
}
this
.
hideFormatModal
();
}
render
():
React
.
ReactNode
{
const
{
is
ShowFormatModal
,
formatStr
}
=
this
.
state
;
const
{
is
HidenInfo
,
typeInfo
,
info
}
=
this
.
state
;
const
trialId
=
this
.
props
.
trialId
;
const
trial
=
TRIALS
.
getTrial
(
trialId
);
const
trialLink
:
string
=
`
${
MANAGER_IP
}
/trial-jobs/
${
trialId
}
`
;
const
logPathRow
=
trial
.
info
.
logPath
||
'
This trial
\'
s log path is not available.
'
;
const
multiProgress
=
trial
.
info
.
hyperParameters
===
undefined
?
0
:
trial
.
info
.
hyperParameters
.
length
;
return
(
<
Row
className
=
"openRowContent hyperpar"
>
<
Tabs
tabPosition
=
"left"
className
=
"card"
>
<
TabPane
tab
=
"Parameters"
key
=
"1"
>
{
EXPERIMENT
.
multiPhase
?
<
Row
className
=
"link"
>
Trails for multiphase experiment will return a set of parameters,
we are listing the latest parameter in webportal.
<
br
/>
For the entire parameter set, please refer to the following
"
<
a
href
=
{
trialLink
}
rel
=
"noopener noreferrer"
target
=
"_blank"
style
=
{
{
marginLeft
:
2
}
}
>
{
trialLink
}
</
a
>
"
<
br
/>
Current Phase:
{
multiProgress
}
.
</
Row
>
:
<
div
/>
}
{
trial
.
info
.
hyperParameters
!==
undefined
?
<
Row
id
=
"description"
>
<
Row
className
=
"bgHyper"
>
<
JSONTree
hideRoot
=
{
true
}
shouldExpandNode
=
{
():
boolean
=>
true
}
// default expandNode
getItemString
=
{
():
any
=>
(<
span
/>)
}
// remove the {} items
data
=
{
trial
.
description
.
parameters
}
/>
</
Row
>
<
Row
className
=
"copy"
>
<
Button
onClick
=
{
this
.
showFormatModal
.
bind
(
this
,
trial
)
}
>
Copy as json
</
Button
>
</
Row
>
</
Row
>
:
<
Row
className
=
"logpath"
>
<
span
className
=
"logName"
style
=
{
{
marginRight
:
2
}
}
>
Error:
</
span
>
<
span
className
=
"error"
>
'
This trial
'
s parameters are not available.
'
</
span
>
</
Row
>
}
</
TabPane
>
<
TabPane
tab
=
"Log"
key
=
"2"
>
{
// FIXME: this should not be handled in web UI side
EXPERIMENT
.
trainingServicePlatform
!==
'
local
'
?
<
PaiTrialLog
logStr
=
{
logPathRow
}
id
=
{
trialId
}
logCollection
=
{
EXPERIMENT
.
logCollectionEnabled
}
/>
:
<
TrialLog
logStr
=
{
logPathRow
}
id
=
{
trialId
}
/>
}
</
TabPane
>
</
Tabs
>
<
Modal
title
=
"Format"
okText
=
"Copy"
centered
=
{
true
}
visible
=
{
isShowFormatModal
}
onCancel
=
{
this
.
hideFormatModal
}
maskClosable
=
{
false
}
// click mongolian layer don't close modal
onOk
=
{
this
.
copyParams
}
destroyOnClose
=
{
true
}
width
=
"60%"
className
=
"format"
>
{
/* write string in pre to show format string */
}
<
pre
className
=
"formatStr"
>
{
formatStr
}
</
pre
>
</
Modal
>
</
Row
>
<
Stack
className
=
"openRow"
>
<
Stack
className
=
"openRowContent"
>
<
Pivot
>
<
PivotItem
headerText
=
"Parameters"
key
=
"1"
itemIcon
=
"TestParameter"
>
{
EXPERIMENT
.
multiPhase
?
<
Stack
className
=
"link"
>
{
`
Trails for multiphase experiment will return a set of parameters,
we are listing the latest parameter in webportal.
For the entire parameter set, please refer to the following "
`
}
<
a
href
=
{
trialLink
}
rel
=
"noopener noreferrer"
target
=
"_blank"
>
{
trialLink
}
</
a
>
{
`".`
}
<
div
>
Current Phase:
{
multiProgress
}
.
</
div
>
</
Stack
>
:
null
}
{
trial
.
info
.
hyperParameters
!==
undefined
?
<
Stack
id
=
"description"
>
<
Stack
className
=
"bgHyper"
>
<
JSONTree
hideRoot
=
{
true
}
shouldExpandNode
=
{
():
boolean
=>
true
}
// default expandNode
getItemString
=
{
():
null
=>
null
}
// remove the {} items
data
=
{
trial
.
description
.
parameters
}
/>
</
Stack
>
<
Stack
horizontal
className
=
"copy"
>
<
PrimaryButton
onClick
=
{
this
.
copyParams
.
bind
(
this
,
trial
)
}
text
=
"Copy as json"
styles
=
{
{
root
:
{
width
:
128
,
marginRight
:
10
}
}
}
/>
{
/* copy success | failed message info */
}
{
!
isHidenInfo
&&
<
MessageInfo
typeInfo
=
{
typeInfo
}
info
=
{
info
}
/>
}
</
Stack
>
</
Stack
>
:
<
Stack
className
=
"logpath"
>
<
span
className
=
"logName"
>
Error:
</
span
>
<
span
className
=
"error"
>
{
`This trial's parameters are not available.'`
}
</
span
>
</
Stack
>
}
</
PivotItem
>
<
PivotItem
headerText
=
"Log"
key
=
"2"
itemIcon
=
"M365InvoicingLogo"
>
{
// FIXME: this should not be handled in web UI side
EXPERIMENT
.
trainingServicePlatform
!==
'
local
'
?
<
PaiTrialLog
logStr
=
{
logPathRow
}
id
=
{
trialId
}
logCollection
=
{
EXPERIMENT
.
logCollectionEnabled
}
/>
:
<
TrialLog
logStr
=
{
logPathRow
}
id
=
{
trialId
}
/>
}
</
PivotItem
>
</
Pivot
>
</
Stack
>
</
Stack
>
);
}
}
...
...
src/webui/src/components/public-child/PaiTrialChild.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
{
Row
}
from
'
antd
'
;
import
{
DOWNLOAD_IP
}
from
'
../../static/const
'
;
interface
PaiTrialChildProps
{
...
...
@@ -24,7 +23,7 @@ class PaiTrialChild extends React.Component<PaiTrialChildProps, {}> {
?
<
div
/>
:
<
Row
>
<
div
>
{
logCollect
?
...
...
@@ -39,7 +38,7 @@ class PaiTrialChild extends React.Component<PaiTrialChildProps, {}> {
:
<
span
>
trial stdout:
{
logString
}
</
span
>
}
</
Row
>
</
div
>
}
</
div
>
);
...
...
src/webui/src/components/public-child/PaiTrialLog.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
{
Row
}
from
'
antd
'
;
import
{
DOWNLOAD_IP
}
from
'
../../static/const
'
;
import
PaiTrialChild
from
'
./PaiTrialChild
'
;
import
LogPathChild
from
'
./LogPathChild
'
;
...
...
@@ -30,11 +29,11 @@ class PaitrialLog extends React.Component<PaitrialLogProps, {}> {
{
isTwopath
?
<
Row
>
<
div
>
{
logCollection
?
<
Row
>
<
div
>
<
a
target
=
"_blank"
rel
=
"noopener noreferrer"
...
...
@@ -44,9 +43,9 @@ class PaitrialLog extends React.Component<PaitrialLogProps, {}> {
Trial stdout
</
a
>
<
a
target
=
"_blank"
rel
=
"noopener noreferrer"
href
=
{
logStr
.
split
(
'
,
'
)[
1
]
}
>
hdfsLog
</
a
>
</
Row
>
</
div
>
:
<
Row
>
<
div
>
<
LogPathChild
eachLogpath
=
{
logStr
.
split
(
'
,
'
)[
0
]
}
logName
=
"Trial stdout:"
...
...
@@ -55,9 +54,9 @@ class PaitrialLog extends React.Component<PaitrialLogProps, {}> {
eachLogpath
=
{
logStr
.
split
(
'
,
'
)[
1
]
}
logName
=
"Log on HDFS:"
/>
</
Row
>
</
div
>
}
</
Row
>
</
div
>
:
<
PaiTrialChild
logString
=
{
logStr
}
...
...
src/webui/src/components/trial-detail/DefaultMetricPoint.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
{
Switch
}
from
'
antd
'
;
import
{
Toggle
,
Stack
}
from
'
office-ui-fabric-react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
Trial
}
from
'
../../static/model/trial
'
;
import
{
TooltipForAccuracy
,
EventMap
}
from
'
../../static/interface
'
;
require
(
'
echarts/lib/chart/scatter
'
);
require
(
'
echarts/lib/component/tooltip
'
);
require
(
'
echarts/lib/component/title
'
);
import
'
echarts/lib/chart/scatter
'
;
import
'
echarts/lib/component/tooltip
'
;
import
'
echarts/lib/component/title
'
;
const
EmptyGraph
=
{
grid
:
{
left
:
'
8%
'
...
...
@@ -18,9 +19,9 @@ const EmptyGraph = {
yAxis
:
{
name
:
'
Default metric
'
,
type
:
'
value
'
,
scale
:
true
,
}
};
interface
DefaultPointProps
{
trialIds
:
string
[];
visible
:
boolean
;
...
...
@@ -28,7 +29,7 @@ interface DefaultPointProps {
}
interface
DefaultPointState
{
bestCurveEnabled
:
boolean
;
bestCurveEnabled
?
:
boolean
|
undefined
;
startY
:
number
;
// dataZoomY
endY
:
number
;
}
...
...
@@ -39,11 +40,11 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
this
.
state
=
{
bestCurveEnabled
:
false
,
startY
:
0
,
// dataZoomY
endY
:
100
,
endY
:
100
};
}
loadDefault
=
(
checked
:
boolean
):
void
=>
{
loadDefault
=
(
ev
:
React
.
MouseEvent
<
HTMLElement
>
,
checked
?
:
boolean
):
void
=>
{
this
.
setState
({
bestCurveEnabled
:
checked
});
}
...
...
@@ -51,7 +52,59 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
return
nextProps
.
visible
;
}
generateScatterSeries
=
(
trials
:
Trial
[]):
any
=>
{
metricDataZoom
=
(
e
:
EventMap
):
void
=>
{
if
(
e
.
batch
!==
undefined
)
{
this
.
setState
(()
=>
({
startY
:
(
e
.
batch
[
0
].
start
!==
null
?
e
.
batch
[
0
].
start
:
0
),
endY
:
(
e
.
batch
[
0
].
end
!==
null
?
e
.
batch
[
0
].
end
:
100
)
}));
}
}
generateGraphConfig
(
maxSequenceId
:
number
):
any
{
const
{
startY
,
endY
}
=
this
.
state
;
return
{
grid
:
{
left
:
'
8%
'
,
},
tooltip
:
{
trigger
:
'
item
'
,
enterable
:
true
,
position
:
(
point
:
number
[],
data
:
TooltipForAccuracy
):
number
[]
=>
(
[(
data
.
data
[
0
]
<
maxSequenceId
?
point
[
0
]
:
(
point
[
0
]
-
300
)),
80
]
),
formatter
:
(
data
:
TooltipForAccuracy
):
React
.
ReactNode
=>
(
'
<div class="tooldetailAccuracy">
'
+
'
<div>Trial No.:
'
+
data
.
data
[
0
]
+
'
</div>
'
+
'
<div>Default metric:
'
+
data
.
data
[
1
]
+
'
</div>
'
+
'
<div>Parameters: <pre>
'
+
JSON
.
stringify
(
data
.
data
[
2
],
null
,
4
)
+
'
</pre></div>
'
+
'
</div>
'
),
},
dataZoom
:
[
{
id
:
'
dataZoomY
'
,
type
:
'
inside
'
,
yAxisIndex
:
[
0
],
filterMode
:
'
empty
'
,
start
:
startY
,
end
:
endY
}
],
xAxis
:
{
name
:
'
Trial
'
,
type
:
'
category
'
,
},
yAxis
:
{
name
:
'
Default metric
'
,
type
:
'
value
'
,
scale
:
true
,
},
series
:
undefined
,
};
}
generateScatterSeries
(
trials
:
Trial
[]):
any
{
const
data
=
trials
.
map
(
trial
=>
[
trial
.
sequenceId
,
trial
.
accuracy
,
...
...
@@ -63,27 +116,24 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
data
,
};
}
generateBestCurveSeries
=
(
trials
:
Trial
[]):
any
=>
{
generateBestCurveSeries
(
trials
:
Trial
[]):
any
{
let
best
=
trials
[
0
];
const
data
=
[[
best
.
sequenceId
,
best
.
accuracy
,
best
.
description
.
parameters
]];
for
(
let
i
=
1
;
i
<
trials
.
length
;
i
++
)
{
const
trial
=
trials
[
i
];
if
(
trial
.
accuracy
!==
undefined
)
{
if
(
best
.
accuracy
!==
undefined
)
{
const
delta
=
trial
.
accuracy
-
best
.
accuracy
;
const
better
=
(
EXPERIMENT
.
optimizeMode
===
'
minimize
'
)
?
(
delta
<
0
)
:
(
delta
>
0
);
if
(
better
)
{
data
.
push
([
trial
.
sequenceId
,
trial
.
accuracy
,
trial
.
description
.
parameters
]);
best
=
trial
;
}
else
{
data
.
push
([
trial
.
sequenceId
,
best
.
accuracy
,
trial
.
description
.
parameters
]);
}
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const
delta
=
trial
.
accuracy
!
-
best
.
accuracy
!
;
const
better
=
(
EXPERIMENT
.
optimizeMode
===
'
minimize
'
)
?
(
delta
<
0
)
:
(
delta
>
0
);
if
(
better
)
{
data
.
push
([
trial
.
sequenceId
,
trial
.
accuracy
,
trial
.
description
.
parameters
]);
best
=
trial
;
}
else
{
data
.
push
([
trial
.
sequenceId
,
best
.
accuracy
,
trial
.
description
.
parameters
]);
}
}
return
{
type
:
'
line
'
,
lineStyle
:
{
color
:
'
#FF6600
'
},
...
...
@@ -98,24 +148,26 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
return
(
<
div
>
<
div
className
=
"default-metric"
>
<
div
className
=
"position"
>
<
span
className
=
"bold"
>
Optimization curve
</
span
>
<
Switch
defaultChecked
=
{
false
}
onChange
=
{
this
.
loadDefault
}
/>
</
div
>
<
Stack
horizontalAlign
=
"end"
className
=
"default-metric"
>
<
Toggle
label
=
"Optimization curve"
inlineLabel
onChange
=
{
this
.
loadDefault
}
/>
</
Stack
>
<
div
className
=
"default-metric-graph"
>
<
ReactEcharts
option
=
{
graph
}
style
=
{
{
width
:
'
100%
'
,
height
:
402
,
margin
:
'
0 auto
'
,
}
}
theme
=
"my_theme"
notMerge
=
{
true
}
// update now
onEvents
=
{
onEvents
}
/>
<
div
className
=
"default-metric-noData"
>
{
accNodata
}
</
div
>
</
div
>
<
ReactEcharts
option
=
{
graph
}
style
=
{
{
width
:
'
100%
'
,
height
:
402
,
margin
:
'
0 auto
'
,
}
}
theme
=
"my_theme"
notMerge
=
{
true
}
// update now
onEvents
=
{
onEvents
}
/>
<
div
className
=
"showMess"
>
{
accNodata
}
</
div
>
</
div
>
);
}
...
...
@@ -133,58 +185,6 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
}
return
graph
;
}
private
generateGraphConfig
(
maxSequenceId
:
number
):
any
{
const
{
startY
,
endY
}
=
this
.
state
;
return
{
grid
:
{
left
:
'
8%
'
,
},
tooltip
:
{
trigger
:
'
item
'
,
enterable
:
true
,
position
:
(
point
:
number
[],
data
:
TooltipForAccuracy
):
number
[]
=>
(
[(
data
.
data
[
0
]
<
maxSequenceId
?
point
[
0
]
:
(
point
[
0
]
-
300
)),
80
]
),
formatter
:
(
data
:
TooltipForAccuracy
):
any
=>
(
'
<div class="tooldetailAccuracy">
'
+
'
<div>Trial No.:
'
+
data
.
data
[
0
]
+
'
</div>
'
+
'
<div>Default metric:
'
+
data
.
data
[
1
]
+
'
</div>
'
+
'
<div>Parameters: <pre>
'
+
JSON
.
stringify
(
data
.
data
[
2
],
null
,
4
)
+
'
</pre></div>
'
+
'
</div>
'
),
},
dataZoom
:
[
{
id
:
'
dataZoomY
'
,
type
:
'
inside
'
,
yAxisIndex
:
[
0
],
filterMode
:
'
empty
'
,
start
:
startY
,
end
:
endY
}
],
xAxis
:
{
name
:
'
Trial
'
,
type
:
'
category
'
,
},
yAxis
:
{
name
:
'
Default metric
'
,
type
:
'
value
'
,
scale
:
true
,
},
series
:
undefined
,
};
}
private
metricDataZoom
=
(
e
:
EventMap
):
void
=>
{
if
(
e
.
batch
!==
undefined
)
{
this
.
setState
(()
=>
({
startY
:
(
e
.
batch
[
0
].
start
!==
null
?
e
.
batch
[
0
].
start
:
0
),
endY
:
(
e
.
batch
[
0
].
end
!==
null
?
e
.
batch
[
0
].
end
:
100
)
}));
}
}
}
export
default
DefaultPoint
;
src/webui/src/components/trial-detail/Duration.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
{
TableObj
,
EventMap
}
from
'
src
/static/interface
'
;
import
{
filterDuration
}
from
'
src
/static/function
'
;
require
(
'
echarts/lib/chart/bar
'
)
;
require
(
'
echarts/lib/component/tooltip
'
)
;
require
(
'
echarts/lib/component/title
'
)
;
import
{
TableObj
,
EventMap
}
from
'
../..
/static/interface
'
;
// eslint-disable-line no-unused-vars
import
{
filterDuration
}
from
'
../..
/static/function
'
;
import
'
echarts/lib/chart/bar
'
;
import
'
echarts/lib/component/tooltip
'
;
import
'
echarts/lib/component/title
'
;
interface
Runtrial
{
trialId
:
Array
<
string
>
;
trialId
:
string
[]
;
trialTime
:
number
[];
}
...
...
@@ -19,6 +19,7 @@ interface DurationProps {
interface
DurationState
{
startDuration
:
number
;
// for record data zoom
endDuration
:
number
;
durationSource
:
{};
}
class
Duration
extends
React
.
Component
<
DurationProps
,
DurationState
>
{
...
...
@@ -29,6 +30,59 @@ class Duration extends React.Component<DurationProps, DurationState> {
this
.
state
=
{
startDuration
:
0
,
// for record data zoom
endDuration
:
100
,
durationSource
:
this
.
initDuration
(
this
.
props
.
source
),
};
}
initDuration
=
(
source
:
Array
<
TableObj
>
):
any
=>
{
const
trialId
:
number
[]
=
[];
const
trialTime
:
number
[]
=
[];
const
trialJobs
=
source
.
filter
(
filterDuration
);
trialJobs
.
forEach
(
item
=>
{
trialId
.
push
(
item
.
sequenceId
);
trialTime
.
push
(
item
.
duration
);
});
return
{
tooltip
:
{
trigger
:
'
axis
'
,
axisPointer
:
{
type
:
'
shadow
'
}
},
grid
:
{
bottom
:
'
3%
'
,
containLabel
:
true
,
left
:
'
1%
'
,
right
:
'
5%
'
},
dataZoom
:
[
{
id
:
'
dataZoomY
'
,
type
:
'
inside
'
,
yAxisIndex
:
[
0
],
filterMode
:
'
empty
'
,
start
:
0
,
end
:
100
},
],
xAxis
:
{
name
:
'
Time/s
'
,
type
:
'
value
'
,
},
yAxis
:
{
name
:
'
Trial No.
'
,
type
:
'
category
'
,
data
:
trialId
,
nameTextStyle
:
{
padding
:
[
0
,
0
,
0
,
30
]
}
},
series
:
[{
type
:
'
bar
'
,
data
:
trialTime
}]
};
}
...
...
@@ -45,7 +99,7 @@ class Duration extends React.Component<DurationProps, DurationState> {
bottom
:
'
3%
'
,
containLabel
:
true
,
left
:
'
1%
'
,
right
:
'
4
%
'
right
:
'
5
%
'
},
dataZoom
:
[
{
...
...
@@ -64,7 +118,10 @@ class Duration extends React.Component<DurationProps, DurationState> {
yAxis
:
{
name
:
'
Trial
'
,
type
:
'
category
'
,
data
:
dataObj
.
trialId
data
:
dataObj
.
trialId
,
nameTextStyle
:
{
padding
:
[
0
,
0
,
0
,
30
]
}
},
series
:
[{
type
:
'
bar
'
,
...
...
@@ -73,11 +130,11 @@ class Duration extends React.Component<DurationProps, DurationState> {
};
}
drawDurationGraph
=
(
source
:
Array
<
TableObj
>
):
any
=>
{
drawDurationGraph
=
(
source
:
Array
<
TableObj
>
):
void
=>
{
// why this function run two times when props changed?
const
trialId
:
Array
<
string
>
=
[];
const
trialId
:
string
[]
=
[];
const
trialTime
:
number
[]
=
[];
const
trialRun
:
Array
<
Runtrial
>
=
[];
const
trialRun
:
Runtrial
[]
=
[];
const
trialJobs
=
source
.
filter
(
filterDuration
);
Object
.
keys
(
trialJobs
).
map
(
item
=>
{
const
temp
=
trialJobs
[
item
];
...
...
@@ -88,7 +145,21 @@ class Duration extends React.Component<DurationProps, DurationState> {
trialId
:
trialId
,
trialTime
:
trialTime
});
return
this
.
getOption
(
trialRun
[
0
]);
this
.
setState
({
durationSource
:
this
.
getOption
(
trialRun
[
0
])
});
}
componentDidMount
():
void
{
const
{
source
}
=
this
.
props
;
this
.
drawDurationGraph
(
source
);
}
componentWillReceiveProps
(
nextProps
:
DurationProps
):
void
{
const
{
whichGraph
,
source
}
=
nextProps
;
if
(
whichGraph
===
'
3
'
)
{
this
.
drawDurationGraph
(
source
);
}
}
shouldComponentUpdate
(
nextProps
:
DurationProps
):
boolean
{
...
...
@@ -117,15 +188,13 @@ class Duration extends React.Component<DurationProps, DurationState> {
}
render
():
React
.
ReactNode
{
const
{
source
}
=
this
.
props
;
const
graph
=
this
.
drawDurationGraph
(
source
);
const
{
durationSource
}
=
this
.
state
;
const
onEvents
=
{
'
dataZoom
'
:
this
.
durationDataZoom
};
return
(
<
div
>
<
ReactEcharts
option
=
{
graph
}
style
=
{
{
width
:
'
9
5
%
'
,
height
:
412
,
margin
:
'
0 auto
'
}
}
option
=
{
durationSource
}
style
=
{
{
width
:
'
9
4
%
'
,
height
:
412
,
margin
:
'
0 auto
'
,
marginTop
:
15
}
}
theme
=
"my_theme"
notMerge
=
{
true
}
// update now
onEvents
=
{
onEvents
}
...
...
src/webui/src/components/trial-detail/Intermediate.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
{
Row
,
Button
,
Switch
}
from
'
antd
'
;
import
{
Stack
,
PrimaryButton
,
Toggle
,
IStackTokens
}
from
'
office-ui-fabric-react
'
;
import
{
TooltipForIntermediate
,
TableObj
,
Intermedia
,
EventMap
}
from
'
../../static/interface
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
require
(
'
echarts/lib/component/tooltip
'
);
require
(
'
echarts/lib/component/title
'
);
import
'
echarts/lib/component/tooltip
'
;
import
'
echarts/lib/component/title
'
;
const
stackTokens
:
IStackTokens
=
{
childrenGap
:
20
};
interface
IntermediateState
{
detailSource
:
Array
<
TableObj
>
;
...
...
@@ -11,7 +15,7 @@ interface IntermediateState {
filterSource
:
Array
<
TableObj
>
;
eachIntermediateNum
:
number
;
// trial's intermediate number count
isLoadconfirmBtn
:
boolean
;
isFilter
:
boolean
;
isFilter
?
:
boolean
|
undefined
;
length
:
number
;
clickCounts
:
number
;
// user filter intermediate click confirm btn's counts
startMediaY
:
number
;
...
...
@@ -26,9 +30,9 @@ interface IntermediateProps {
class
Intermediate
extends
React
.
Component
<
IntermediateProps
,
IntermediateState
>
{
static
intervalMediate
=
1
;
public
pointInput
:
HTMLInputElement
|
null
;
public
minValInput
:
HTMLInputElement
|
null
;
public
maxValInput
:
HTMLInputElement
|
null
;
public
pointInput
!
:
HTMLInputElement
|
null
;
public
minValInput
!
:
HTMLInputElement
|
null
;
public
maxValInput
!
:
HTMLInputElement
|
null
;
constructor
(
props
:
IntermediateProps
)
{
super
(
props
);
...
...
@@ -65,7 +69,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
});
// find max intermediate number
trialIntermediate
.
sort
((
a
,
b
)
=>
{
return
(
b
.
data
.
length
-
a
.
data
.
length
);
});
const
legend
:
Array
<
string
>
=
[];
const
legend
:
string
[]
=
[];
// max length
const
length
=
trialIntermediate
[
0
].
data
.
length
;
const
xAxis
:
number
[]
=
[];
...
...
@@ -87,7 +91,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
return
[
point
[
0
]
-
300
,
80
];
}
},
formatter
:
function
(
data
:
TooltipForIntermediate
):
any
{
formatter
:
function
(
data
:
TooltipForIntermediate
):
React
.
ReactNode
{
const
trialId
=
data
.
seriesName
;
let
obj
=
{};
const
temp
=
trialIntermediate
.
find
(
key
=>
key
.
name
===
trialId
);
...
...
@@ -116,7 +120,8 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
},
yAxis
:
{
type
:
'
value
'
,
name
:
'
Metric
'
name
:
'
Metric
'
,
scale
:
true
,
},
dataZoom
:
[
{
...
...
@@ -195,7 +200,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
});
}
switchTurn
=
(
checked
:
boolean
):
void
=>
{
switchTurn
=
(
ev
:
React
.
MouseEvent
<
HTMLElement
>
,
checked
?
:
boolean
):
void
=>
{
this
.
setState
({
isFilter
:
checked
});
if
(
checked
===
false
)
{
this
.
drawIntermediate
(
this
.
props
.
source
);
...
...
@@ -226,62 +231,18 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
}
}
shouldComponentUpdate
(
nextProps
:
IntermediateProps
,
nextState
:
IntermediateState
):
boolean
{
const
{
whichGraph
,
source
}
=
nextProps
;
const
beforeGraph
=
this
.
props
.
whichGraph
;
if
(
whichGraph
===
'
4
'
)
{
const
{
isFilter
,
length
,
clickCounts
}
=
nextState
;
const
beforeLength
=
this
.
state
.
length
;
const
beforeSource
=
this
.
props
.
source
;
const
beforeClickCounts
=
this
.
state
.
clickCounts
;
if
(
isFilter
!==
this
.
state
.
isFilter
)
{
return
true
;
}
if
(
clickCounts
!==
beforeClickCounts
)
{
return
true
;
}
if
(
isFilter
===
false
)
{
if
(
whichGraph
!==
beforeGraph
)
{
return
true
;
}
if
(
length
!==
beforeLength
)
{
return
true
;
}
if
(
beforeSource
.
length
!==
source
.
length
)
{
return
true
;
}
if
(
beforeSource
[
beforeSource
.
length
-
1
]
!==
undefined
)
{
if
(
source
[
source
.
length
-
1
].
description
.
intermediate
.
length
!==
beforeSource
[
beforeSource
.
length
-
1
].
description
.
intermediate
.
length
)
{
return
true
;
}
if
(
source
[
source
.
length
-
1
].
duration
!==
beforeSource
[
beforeSource
.
length
-
1
].
duration
)
{
return
true
;
}
if
(
source
[
source
.
length
-
1
].
status
!==
beforeSource
[
beforeSource
.
length
-
1
].
status
)
{
return
true
;
}
}
}
}
return
false
;
}
render
():
React
.
ReactNode
{
const
{
interSource
,
isLoadconfirmBtn
,
isFilter
}
=
this
.
state
;
const
IntermediateEvents
=
{
'
dataZoom
'
:
this
.
intermediateDataZoom
};
return
(
<
div
>
{
/* style in para.scss */
}
<
Row
className
=
"meline intermediate"
>
<
Stack
horizontal
horizontalAlign
=
"end"
tokens
=
{
stackTokens
}
className
=
"meline intermediate"
>
{
isFilter
?
<
span
style
=
{
{
marginRight
:
15
}
}
>
<
div
>
<
span
className
=
"filter-x"
>
# Intermediate result
</
span
>
<
input
// placeholder="point"
...
...
@@ -298,34 +259,31 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
// placeholder="range"
ref
=
{
(
input
):
any
=>
this
.
maxValInput
=
input
}
/>
<
Button
type
=
"primary"
className
=
"changeBtu tableButton"
<
PrimaryButton
text
=
"Confirm"
onClick
=
{
this
.
filterLines
}
disabled
=
{
isLoadconfirmBtn
}
>
Confirm
</
Button
>
</
span
>
/>
</
div
>
:
null
}
{
/* filter message */
}
<
span
>
Filter
</
span
>
<
Switch
defaultChecked
=
{
false
}
onChange
=
{
this
.
switchTurn
}
/>
</
Row
>
<
Row
className
=
"intermediate-graph"
>
<
Stack
horizontal
className
=
"filter-toggle"
>
<
span
>
Filter
</
span
>
<
Toggle
onChange
=
{
this
.
switchTurn
}
/>
</
Stack
>
</
Stack
>
<
div
className
=
"intermediate-graph"
>
<
ReactEcharts
option
=
{
interSource
}
style
=
{
{
width
:
'
100%
'
,
height
:
4
18
,
margin
:
'
0 auto
'
}
}
style
=
{
{
width
:
'
100%
'
,
height
:
4
00
,
margin
:
'
0 auto
'
}
}
notMerge
=
{
true
}
// update now
onEvents
=
{
IntermediateEvents
}
/>
<
div
className
=
"yAxis"
>
# Intermediate result
</
div
>
</
Row
>
</
div
>
</
div
>
);
}
...
...
src/webui/src/components/trial-detail/Para.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
{
filterByStatus
}
from
'
../../static/function
'
;
import
{
Row
,
Col
,
Select
,
Button
,
message
}
from
'
antd
'
;
import
{
ParaObj
,
Dimobj
,
TableObj
}
from
'
../../static/interface
'
;
const
Option
=
Select
.
Option
;
require
(
'
echarts/lib/chart/parallel
'
);
require
(
'
echarts/lib/component/tooltip
'
);
require
(
'
echarts/lib/component/title
'
);
require
(
'
echarts/lib/component/visualMap
'
);
require
(
'
../../static/style/para.scss
'
);
require
(
'
../../static/style/button.scss
'
);
import
{
Stack
,
PrimaryButton
,
Dropdown
,
IDropdownOption
,
}
from
'
office-ui-fabric-react
'
;
// eslint-disable-line no-unused-vars
import
{
ParaObj
,
Dimobj
,
TableObj
}
from
'
../../static/interface
'
;
// eslint-disable-line no-unused-vars
import
'
echarts/lib/chart/parallel
'
;
import
'
echarts/lib/component/tooltip
'
;
import
'
echarts/lib/component/title
'
;
import
'
echarts/lib/component/visualMap
'
;
import
'
../../static/style/para.scss
'
;
import
'
../../static/style/button.scss
'
;
interface
ParaState
{
// paraSource: Array<TableObj>;
option
:
object
;
paraBack
:
ParaObj
;
dimName
:
Array
<
string
>
;
swapAxisArr
:
Array
<
string
>
;
dimName
:
string
[]
;
swapAxisArr
:
string
[]
;
percent
:
number
;
paraNodata
:
string
;
max
:
number
;
// graph color bar limit
...
...
@@ -25,6 +24,9 @@ interface ParaState {
succeedRenderCount
:
number
;
// all succeed trials number
clickCounts
:
number
;
isLoadConfirm
:
boolean
;
// office-fabric-ui
selectedItem
?:
{
key
:
string
|
number
|
undefined
};
// percent Selector
swapyAxis
?:
string
[];
// yAxis Selector
}
interface
ParaProps
{
...
...
@@ -33,11 +35,6 @@ interface ParaProps {
whichGraph
:
string
;
}
message
.
config
({
top
:
250
,
duration
:
2
,
});
class
Para
extends
React
.
Component
<
ParaProps
,
ParaState
>
{
private
chartMulineStyle
=
{
...
...
@@ -69,14 +66,15 @@ class Para extends React.Component<ParaProps, ParaState> {
sutrialCount
:
10000000
,
succeedRenderCount
:
10000000
,
clickCounts
:
1
,
isLoadConfirm
:
false
isLoadConfirm
:
false
,
swapyAxis
:
[]
};
}
getParallelAxis
=
(
dimName
:
Array
<
string
>
,
parallelAxis
:
Array
<
Dimobj
>
,
accPara
:
number
[],
eachTrialParams
:
Array
<
string
>
,
dimName
:
string
[]
,
parallelAxis
:
Array
<
Dimobj
>
,
accPara
:
number
[],
eachTrialParams
:
string
[]
,
lengthofTrials
:
number
):
void
=>
{
// get data for every lines. if dim is choice type, number -> toString()
...
...
@@ -128,7 +126,7 @@ class Para extends React.Component<ParaProps, ParaState> {
const
lenOfDataSource
:
number
=
dataSource
.
length
;
const
accPara
:
number
[]
=
[];
// specific value array
const
eachTrialParams
:
Array
<
string
>
=
[];
const
eachTrialParams
:
string
[]
=
[];
// experiment interface search space obj
const
searchRange
=
searchSpace
!==
undefined
?
JSON
.
parse
(
searchSpace
)
:
''
;
// nest search space
...
...
@@ -147,8 +145,8 @@ class Para extends React.Component<ParaProps, ParaState> {
let
i
=
0
;
if
(
isNested
===
false
)
{
for
(
i
;
i
<
dimName
.
length
;
i
++
)
{
const
data
:
string
[]
=
[];
const
searchKey
=
searchRange
[
dimName
[
i
]];
const
data
:
Array
<
string
>
=
[];
switch
(
searchKey
.
_type
)
{
case
'
uniform
'
:
case
'
quniform
'
:
...
...
@@ -220,10 +218,11 @@ class Para extends React.Component<ParaProps, ParaState> {
}
else
{
for
(
i
;
i
<
dimName
.
length
;
i
++
)
{
const
searchKey
=
searchRange
[
dimName
[
i
]];
const
data
:
Array
<
string
>
=
[];
const
data
:
string
[]
=
[];
let
j
=
0
;
switch
(
searchKey
.
_type
)
{
case
'
choice
'
:
for
(
let
j
=
0
;
j
<
searchKey
.
_value
.
length
;
j
++
)
{
for
(
j
;
j
<
searchKey
.
_value
.
length
;
j
++
)
{
const
item
=
searchKey
.
_value
[
j
];
Object
.
keys
(
item
).
map
(
key
=>
{
if
(
key
!==
'
_name
'
&&
key
!==
'
_type
'
)
{
...
...
@@ -362,10 +361,15 @@ class Para extends React.Component<ParaProps, ParaState> {
}
// get percent value number
percentNum
=
(
value
:
string
):
void
=>
{
const
vals
=
parseFloat
(
value
);
this
.
setState
({
percent
:
vals
},
()
=>
{
this
.
reInit
();
});
// percentNum = (value: string) => {
percentNum
=
(
event
:
React
.
FormEvent
<
HTMLDivElement
>
,
item
?:
IDropdownOption
):
void
=>
{
// percentNum = (event: React.FormEvent<HTMLDivElement>, item?: ISelectableOption) => {
if
(
item
!==
undefined
)
{
const
vals
=
parseFloat
(
item
!==
undefined
?
item
.
text
:
''
);
this
.
setState
({
percent
:
vals
/
100
,
selectedItem
:
item
},
()
=>
{
this
.
reInit
();
});
}
}
// deal with response data into pic data
...
...
@@ -439,8 +443,24 @@ class Para extends React.Component<ParaProps, ParaState> {
}
// get swap parallel axis
getSwapArr
=
(
value
:
Array
<
string
>
):
void
=>
{
this
.
setState
({
swapAxisArr
:
value
});
getSwapArr
=
(
event
:
React
.
FormEvent
<
HTMLDivElement
>
,
item
?:
IDropdownOption
):
void
=>
{
const
newSelectedItems
=
[...
this
.
state
.
swapyAxis
];
if
(
item
!==
undefined
)
{
if
(
item
.
selected
)
{
// add the option if it's checked
newSelectedItems
.
push
(
item
.
key
as
string
);
}
else
{
// remove the option if it's unchecked
const
currIndex
=
newSelectedItems
.
indexOf
(
item
.
key
as
string
);
if
(
currIndex
>
-
1
)
{
newSelectedItems
.
splice
(
currIndex
,
1
);
}
}
this
.
setState
({
swapAxisArr
:
newSelectedItems
,
swapyAxis
:
newSelectedItems
});
}
}
reInit
=
():
void
=>
{
...
...
@@ -571,80 +591,47 @@ class Para extends React.Component<ParaProps, ParaState> {
}
}
shouldComponentUpdate
(
nextProps
:
ParaProps
,
nextState
:
ParaState
):
boolean
{
const
{
whichGraph
}
=
nextProps
;
const
beforeGraph
=
this
.
props
.
whichGraph
;
if
(
whichGraph
===
'
2
'
)
{
if
(
whichGraph
!==
beforeGraph
)
{
return
true
;
}
const
{
sutrialCount
,
clickCounts
,
succeedRenderCount
}
=
nextState
;
const
beforeCount
=
this
.
state
.
sutrialCount
;
const
beforeClickCount
=
this
.
state
.
clickCounts
;
const
beforeRealRenderCount
=
this
.
state
.
succeedRenderCount
;
if
(
sutrialCount
!==
beforeCount
)
{
return
true
;
}
if
(
succeedRenderCount
!==
beforeRealRenderCount
)
{
return
true
;
}
if
(
clickCounts
!==
beforeClickCount
)
{
return
true
;
}
}
return
false
;
}
render
():
React
.
ReactNode
{
const
{
option
,
paraNodata
,
dimName
,
isLoadConfirm
}
=
this
.
state
;
const
{
option
,
paraNodata
,
dimName
,
isLoadConfirm
,
selectedItem
,
swapyAxis
}
=
this
.
state
;
return
(
<
Row
className
=
"parameter"
>
<
Row
>
<
Col
span
=
{
6
}
/>
<
Col
span
=
{
18
}
>
<
Row
className
=
"meline"
>
<
span
>
Top
</
span
>
<
Select
style
=
{
{
width
:
'
20%
'
,
marginRight
:
10
}
}
placeholder
=
"100%"
optionFilterProp
=
"children"
onSelect
=
{
this
.
percentNum
}
>
<
Option
value
=
"0.2"
>
20%
</
Option
>
<
Option
value
=
"0.5"
>
50%
</
Option
>
<
Option
value
=
"0.8"
>
80%
</
Option
>
<
Option
value
=
"1"
>
100%
</
Option
>
</
Select
>
<
Select
style
=
{
{
width
:
'
60%
'
}
}
mode
=
"multiple"
placeholder
=
"Please select two items to swap"
onChange
=
{
this
.
getSwapArr
}
maxTagCount
=
{
2
}
>
{
dimName
.
map
((
key
,
item
)
=>
{
return
(
<
Option
key
=
{
key
}
value
=
{
dimName
[
item
]
}
>
{
dimName
[
item
]
}
</
Option
>
);
})
}
</
Select
>
<
Button
type
=
"primary"
className
=
"changeBtu tableButton"
onClick
=
{
this
.
swapReInit
}
disabled
=
{
isLoadConfirm
}
>
Confirm
</
Button
>
</
Row
>
</
Col
>
</
Row
>
<
Row
className
=
"searcHyper"
>
<
div
className
=
"parameter"
>
<
Stack
horizontal
className
=
"para-filter"
horizontalAlign
=
"end"
>
<
span
className
=
"para-filter-text"
>
Top
</
span
>
<
Dropdown
selectedKey
=
{
selectedItem
?
selectedItem
.
key
:
undefined
}
onChange
=
{
this
.
percentNum
}
placeholder
=
"100%"
defaultSelectedKeys
=
{
[
0.2
]
}
options
=
{
[
{
key
:
'
0.2
'
,
text
:
'
20%
'
},
{
key
:
'
0.5
'
,
text
:
'
50%
'
},
{
key
:
'
0.8
'
,
text
:
'
80%
'
},
{
key
:
'
1
'
,
text
:
'
100%
'
},
]
}
styles
=
{
{
dropdown
:
{
width
:
300
}
}
}
className
=
"para-filter-percent"
/>
<
Dropdown
placeholder
=
"Select options"
selectedKeys
=
{
swapyAxis
}
onChange
=
{
this
.
getSwapArr
}
multiSelect
options
=
{
dimName
.
map
((
key
,
item
)
=>
{
return
{
key
:
key
,
text
:
dimName
[
item
]
};
})
}
styles
=
{
{
dropdown
:
{
width
:
300
}
}
}
/>
<
PrimaryButton
text
=
"Confirm"
onClick
=
{
this
.
swapReInit
}
disabled
=
{
isLoadConfirm
}
/>
</
Stack
>
<
div
className
=
"searcHyper"
>
<
ReactEcharts
option
=
{
option
}
style
=
{
this
.
chartMulineStyle
}
...
...
@@ -652,8 +639,8 @@ class Para extends React.Component<ParaProps, ParaState> {
notMerge
=
{
true
}
// update now
/>
<
div
className
=
"noneData"
>
{
paraNodata
}
</
div
>
</
Row
>
</
Row
>
</
div
>
</
div
>
);
}
}
...
...
src/webui/src/components/trial-detail/TableList.tsx
View file @
c7187946
import
*
as
React
from
'
react
'
;
import
axios
from
'
axios
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
{
Row
,
Table
,
Button
,
Popconfirm
,
Modal
,
Checkbox
,
Select
,
Icon
}
from
'
antd
'
;
import
{
ColumnProps
}
from
'
antd/lib/table
'
;
const
Option
=
Select
.
Option
;
const
CheckboxGroup
=
Checkbox
.
Group
;
import
{
MANAGER_IP
,
trialJobStatus
,
COLUMN_INDEX
,
COLUMNPro
}
from
'
../../static/const
'
;
import
{
convertDuration
,
formatTimestamp
,
intermediateGraphOption
,
killJob
,
parseMetrics
}
from
'
../../static/function
'
;
import
{
Stack
,
Dropdown
,
DetailsList
,
IDetailsListProps
,
DetailsListLayoutMode
,
PrimaryButton
,
Modal
,
IDropdownOption
,
IColumn
,
Selection
,
SelectionMode
,
IconButton
}
from
'
office-ui-fabric-react
'
;
import
{
LineChart
,
blocked
,
copy
}
from
'
../Buttons/Icon
'
;
import
{
MANAGER_IP
,
COLUMNPro
}
from
'
../../static/const
'
;
import
{
convertDuration
,
formatTimestamp
,
intermediateGraphOption
,
parseMetrics
}
from
'
../../static/function
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
TableRecord
}
from
'
../../static/interface
'
;
import
OpenRow
from
'
../public-child/OpenRow
'
;
import
Compare
from
'
../Modal/Compare
'
;
import
Customize
from
'
../Modal/CustomizedTrial
'
;
import
Details
from
'
../overview/Details
'
;
import
ChangeColumnComponent
from
'
../Modals/ChangeColumnComponent
'
;
import
Compare
from
'
../Modals/Compare
'
;
import
KillJob
from
'
../Modals/Killjob
'
;
import
Customize
from
'
../Modals/CustomizedTrial
'
;
import
{
contentStyles
,
iconButtonStyles
}
from
'
../Buttons/ModalTheme
'
;
import
'
../../static/style/search.scss
'
;
require
(
'
../../static/style/tableStatus.css
'
)
;
require
(
'
../../static/style/logPath.scss
'
)
;
require
(
'
../../static/style/search.scss
'
)
;
require
(
'
../../static/style/table.scss
'
)
;
require
(
'
../../static/style/button.scss
'
)
;
require
(
'
../../static/style/openRow.scss
'
)
;
import
'
../../static/style/tableStatus.css
'
;
import
'
../../static/style/logPath.scss
'
;
import
'
../../static/style/search.scss
'
;
import
'
../../static/style/table.scss
'
;
import
'
../../static/style/button.scss
'
;
import
'
../../static/style/openRow.scss
'
;
const
echarts
=
require
(
'
echarts/lib/echarts
'
);
require
(
'
echarts/lib/chart/line
'
);
require
(
'
echarts/lib/component/tooltip
'
);
...
...
@@ -27,11 +31,12 @@ echarts.registerTheme('my_theme', {
color
:
'
#3c8dbc
'
});
interface
TableListProps
{
pageSize
:
number
;
tableSource
:
Array
<
TableRecord
>
;
columnList
:
Array
<
string
>
;
// user select columnKeys
changeColumn
:
(
val
:
Array
<
string
>
)
=>
void
;
columnList
:
string
[]
;
// user select columnKeys
changeColumn
:
(
val
:
string
[]
)
=>
void
;
trialsUpdateBroadcast
:
number
;
}
...
...
@@ -40,115 +45,29 @@ interface TableListState {
modalVisible
:
boolean
;
isObjFinal
:
boolean
;
isShowColumn
:
boolean
;
selectRows
:
Array
<
TableRecord
>
;
selectRows
:
Array
<
any
>
;
isShowCompareModal
:
boolean
;
selectedRowKeys
:
string
[]
|
number
[];
intermediateData
:
Array
<
object
>
;
// a trial's intermediate results (include dict)
intermediateId
:
string
;
intermediateOtherKeys
:
Array
<
string
>
;
intermediateOtherKeys
:
string
[]
;
isShowCustomizedModal
:
boolean
;
copyTrialId
:
string
;
// user copy trial to submit a new customized trial
isCalloutVisible
:
boolean
;
// kill job button callout [kill or not kill job window]
intermediateKeys
:
string
[];
// intermeidate modal: which key is choosed.
isExpand
:
boolean
;
modalIntermediateWidth
:
number
;
modalIntermediateHeight
:
number
;
tableColumns
:
IColumn
[];
allColumnList
:
string
[];
tableSourceForSort
:
Array
<
TableRecord
>
;
}
interface
ColumnIndex
{
name
:
string
;
index
:
number
;
}
const
AccuracyColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Default metric
'
,
className
:
'
leftTitle
'
,
dataIndex
:
'
accuracy
'
,
sorter
:
(
a
,
b
,
sortOrder
)
=>
{
if
(
a
.
latestAccuracy
===
undefined
)
{
return
sortOrder
===
'
ascend
'
?
1
:
-
1
;
}
else
if
(
b
.
latestAccuracy
===
undefined
)
{
return
sortOrder
===
'
ascend
'
?
-
1
:
1
;
}
else
{
return
a
.
latestAccuracy
-
b
.
latestAccuracy
;
}
},
render
:
(
text
,
record
):
React
.
ReactNode
=>
<
div
>
{
record
.
formattedLatestAccuracy
}
</
div
>
};
const
SequenceIdColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Trial No.
'
,
dataIndex
:
'
sequenceId
'
,
className
:
'
tableHead
'
,
sorter
:
(
a
,
b
)
=>
a
.
sequenceId
-
b
.
sequenceId
};
const
IdColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
ID
'
,
dataIndex
:
'
id
'
,
className
:
'
tableHead leftTitle
'
,
sorter
:
(
a
,
b
)
=>
a
.
id
.
localeCompare
(
b
.
id
),
render
:
(
text
,
record
):
React
.
ReactNode
=>
(
<
div
>
{
record
.
id
}
</
div
>
)
};
const
StartTimeColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Start Time
'
,
dataIndex
:
'
startTime
'
,
sorter
:
(
a
,
b
)
=>
a
.
startTime
-
b
.
startTime
,
render
:
(
text
,
record
):
React
.
ReactNode
=>
(
<
span
>
{
formatTimestamp
(
record
.
startTime
)
}
</
span
>
)
};
const
EndTimeColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
End Time
'
,
dataIndex
:
'
endTime
'
,
sorter
:
(
a
,
b
,
sortOrder
)
=>
{
if
(
a
.
endTime
===
undefined
)
{
return
sortOrder
===
'
ascend
'
?
1
:
-
1
;
}
else
if
(
b
.
endTime
===
undefined
)
{
return
sortOrder
===
'
ascend
'
?
-
1
:
1
;
}
else
{
return
a
.
endTime
-
b
.
endTime
;
}
},
render
:
(
text
,
record
):
React
.
ReactNode
=>
(
<
span
>
{
formatTimestamp
(
record
.
endTime
,
'
--
'
)
}
</
span
>
)
};
const
DurationColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Duration
'
,
dataIndex
:
'
duration
'
,
sorter
:
(
a
,
b
)
=>
a
.
duration
-
b
.
duration
,
render
:
(
text
,
record
):
React
.
ReactNode
=>
(
<
span
className
=
"durationsty"
>
{
convertDuration
(
record
.
duration
)
}
</
span
>
)
};
const
StatusColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Status
'
,
dataIndex
:
'
status
'
,
className
:
'
tableStatus
'
,
render
:
(
text
,
record
):
React
.
ReactNode
=>
(
<
span
className
=
{
`
${
record
.
status
}
commonStyle`
}
>
{
record
.
status
}
</
span
>
),
sorter
:
(
a
,
b
)
=>
a
.
status
.
localeCompare
(
b
.
status
),
filters
:
trialJobStatus
.
map
(
status
=>
({
text
:
status
,
value
:
status
})),
onFilter
:
(
value
,
record
)
=>
(
record
.
status
===
value
)
};
const
IntermediateCountColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Intermediate result
'
,
dataIndex
:
'
intermediateCount
'
,
sorter
:
(
a
,
b
)
=>
a
.
intermediateCount
-
b
.
intermediateCount
,
render
:
(
text
,
record
):
React
.
ReactNode
=>
(
<
span
>
{
`#
${
record
.
intermediateCount
}
`
}
</
span
>
)
};
class
TableList
extends
React
.
Component
<
TableListProps
,
TableListState
>
{
public
intervalTrialLog
=
10
;
public
_trialId
:
string
;
public
tables
:
Table
<
TableRecord
>
|
null
;
public
trialId
!
:
string
;
constructor
(
props
:
TableListProps
)
{
super
(
props
);
...
...
@@ -165,18 +84,164 @@ class TableList extends React.Component<TableListProps, TableListState> {
intermediateId
:
''
,
intermediateOtherKeys
:
[],
isShowCustomizedModal
:
false
,
copyTrialId
:
''
isCalloutVisible
:
false
,
copyTrialId
:
''
,
intermediateKeys
:
[
'
default
'
],
isExpand
:
false
,
modalIntermediateWidth
:
window
.
innerWidth
,
modalIntermediateHeight
:
window
.
innerHeight
,
tableColumns
:
this
.
initTableColumnList
(
this
.
props
.
columnList
),
allColumnList
:
this
.
getAllColumnKeys
(),
tableSourceForSort
:
this
.
props
.
tableSource
};
}
showIntermediateModal
=
async
(
id
:
string
):
Promise
<
void
>
=>
{
// sort for table column
onColumnClick
=
(
ev
:
React
.
MouseEvent
<
HTMLElement
>
,
getColumn
:
IColumn
):
void
=>
{
const
{
tableColumns
}
=
this
.
state
;
const
{
tableSource
}
=
this
.
props
;
const
newColumns
:
IColumn
[]
=
tableColumns
.
slice
();
const
currColumn
:
IColumn
=
newColumns
.
filter
(
item
=>
getColumn
.
key
===
item
.
key
)[
0
];
newColumns
.
forEach
((
newCol
:
IColumn
)
=>
{
if
(
newCol
===
currColumn
)
{
currColumn
.
isSortedDescending
=
!
currColumn
.
isSortedDescending
;
currColumn
.
isSorted
=
true
;
}
else
{
newCol
.
isSorted
=
false
;
newCol
.
isSortedDescending
=
true
;
}
});
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const
newItems
=
this
.
copyAndSort
(
tableSource
,
currColumn
.
fieldName
!
,
currColumn
.
isSortedDescending
);
this
.
setState
({
tableColumns
:
newColumns
,
tableSourceForSort
:
newItems
});
};
private
copyAndSort
<
T
>
(
items
:
T
[],
columnKey
:
string
,
isSortedDescending
?:
boolean
):
T
[]
{
const
key
=
columnKey
as
keyof
T
;
return
items
.
slice
(
0
).
sort
((
a
:
T
,
b
:
T
)
=>
((
isSortedDescending
?
a
[
key
]
<
b
[
key
]
:
a
[
key
]
>
b
[
key
])
?
1
:
-
1
));
}
AccuracyColumnConfig
:
any
=
{
name
:
'
Default metric
'
,
className
:
'
leftTitle
'
,
key
:
'
accuracy
'
,
fieldName
:
'
accuracy
'
,
minWidth
:
200
,
maxWidth
:
300
,
isResizable
:
true
,
data
:
'
number
'
,
onColumnClick
:
this
.
onColumnClick
,
onRender
:
(
item
):
React
.
ReactNode
=>
<
div
>
{
item
.
formattedLatestAccuracy
}
</
div
>
};
SequenceIdColumnConfig
:
any
=
{
name
:
'
Trial No.
'
,
key
:
'
sequenceId
'
,
fieldName
:
'
sequenceId
'
,
minWidth
:
80
,
maxWidth
:
120
,
className
:
'
tableHead
'
,
data
:
'
string
'
,
onColumnClick
:
this
.
onColumnClick
,
};
IdColumnConfig
:
any
=
{
name
:
'
ID
'
,
key
:
'
id
'
,
fieldName
:
'
id
'
,
minWidth
:
150
,
maxWidth
:
200
,
isResizable
:
true
,
data
:
'
string
'
,
onColumnClick
:
this
.
onColumnClick
,
className
:
'
tableHead leftTitle
'
};
StartTimeColumnConfig
:
any
=
{
name
:
'
Start Time
'
,
key
:
'
startTime
'
,
fieldName
:
'
startTime
'
,
minWidth
:
150
,
maxWidth
:
200
,
isResizable
:
true
,
data
:
'
number
'
,
onColumnClick
:
this
.
onColumnClick
,
onRender
:
(
record
):
React
.
ReactNode
=>
(
<
span
>
{
formatTimestamp
(
record
.
startTime
)
}
</
span
>
)
};
EndTimeColumnConfig
:
any
=
{
name
:
'
End Time
'
,
key
:
'
endTime
'
,
fieldName
:
'
endTime
'
,
minWidth
:
150
,
maxWidth
:
200
,
isResizable
:
true
,
data
:
'
number
'
,
onColumnClick
:
this
.
onColumnClick
,
onRender
:
(
record
):
React
.
ReactNode
=>
(
<
span
>
{
formatTimestamp
(
record
.
endTime
,
'
--
'
)
}
</
span
>
)
};
DurationColumnConfig
:
any
=
{
name
:
'
Duration
'
,
key
:
'
duration
'
,
fieldName
:
'
duration
'
,
minWidth
:
150
,
maxWidth
:
200
,
isResizable
:
true
,
data
:
'
number
'
,
onColumnClick
:
this
.
onColumnClick
,
onRender
:
(
record
):
React
.
ReactNode
=>
(
<
span
className
=
"durationsty"
>
{
convertDuration
(
record
.
duration
)
}
</
span
>
)
};
StatusColumnConfig
:
any
=
{
name
:
'
Status
'
,
key
:
'
status
'
,
fieldName
:
'
status
'
,
className
:
'
tableStatus
'
,
minWidth
:
150
,
maxWidth
:
200
,
isResizable
:
true
,
data
:
'
string
'
,
onColumnClick
:
this
.
onColumnClick
,
onRender
:
(
record
):
React
.
ReactNode
=>
(
<
span
className
=
{
`
${
record
.
status
}
commonStyle`
}
>
{
record
.
status
}
</
span
>
),
};
IntermediateCountColumnConfig
:
any
=
{
name
:
'
Intermediate result
'
,
dataIndex
:
'
intermediateCount
'
,
fieldName
:
'
intermediateCount
'
,
minWidth
:
150
,
maxWidth
:
200
,
isResizable
:
true
,
data
:
'
number
'
,
onColumnClick
:
this
.
onColumnClick
,
onRender
:
(
record
):
React
.
ReactNode
=>
(
<
span
>
{
`#
${
record
.
intermediateCount
}
`
}
</
span
>
)
};
showIntermediateModal
=
async
(
id
:
string
,
event
:
React
.
SyntheticEvent
<
EventTarget
>
):
Promise
<
void
>
=>
{
event
.
preventDefault
();
event
.
stopPropagation
();
const
res
=
await
axios
.
get
(
`
${
MANAGER_IP
}
/metric-data/
${
id
}
`
);
if
(
res
.
status
===
200
)
{
const
intermediateArr
:
number
[]
=
[];
// support intermediate result is dict because the last intermediate result is
// final result in a succeed trial, it may be a dict.
// get intermediate result dict keys array
let
otherkeys
:
Array
<
string
>
=
[
'
default
'
];
let
otherkeys
:
string
[]
=
[
'
default
'
];
if
(
res
.
data
.
length
!==
0
)
{
otherkeys
=
Object
.
keys
(
parseMetrics
(
res
.
data
[
0
].
data
));
}
...
...
@@ -202,34 +267,37 @@ class TableList extends React.Component<TableListProps, TableListState> {
// intermediate button click -> intermediate graph for each trial
// support intermediate is dict
selectOtherKeys
=
(
value
:
string
):
void
=>
{
const
isShowDefault
:
boolean
=
value
===
'
default
'
?
true
:
false
;
const
{
intermediateData
,
intermediateId
}
=
this
.
state
;
const
intermediateArr
:
number
[]
=
[];
// just watch default key-val
if
(
isShowDefault
===
true
)
{
Object
.
keys
(
intermediateData
).
map
(
item
=>
{
const
temp
=
parseMetrics
(
intermediateData
[
item
].
data
);
if
(
typeof
temp
===
'
object
'
)
{
intermediateArr
.
push
(
temp
[
value
]);
}
else
{
intermediateArr
.
push
(
temp
);
}
});
}
else
{
Object
.
keys
(
intermediateData
).
map
(
item
=>
{
const
temp
=
parseMetrics
(
intermediateData
[
item
].
data
);
if
(
typeof
temp
===
'
object
'
)
{
intermediateArr
.
push
(
temp
[
value
]);
}
selectOtherKeys
=
(
event
:
React
.
FormEvent
<
HTMLDivElement
>
,
item
?:
IDropdownOption
):
void
=>
{
if
(
item
!==
undefined
)
{
const
value
=
item
.
text
;
const
isShowDefault
:
boolean
=
value
===
'
default
'
?
true
:
false
;
const
{
intermediateData
,
intermediateId
}
=
this
.
state
;
const
intermediateArr
:
number
[]
=
[];
// just watch default key-val
if
(
isShowDefault
===
true
)
{
Object
.
keys
(
intermediateData
).
map
(
item
=>
{
const
temp
=
parseMetrics
(
intermediateData
[
item
].
data
);
if
(
typeof
temp
===
'
object
'
)
{
intermediateArr
.
push
(
temp
[
value
]);
}
else
{
intermediateArr
.
push
(
temp
);
}
});
}
else
{
Object
.
keys
(
intermediateData
).
map
(
item
=>
{
const
temp
=
parseMetrics
(
intermediateData
[
item
].
data
);
if
(
typeof
temp
===
'
object
'
)
{
intermediateArr
.
push
(
temp
[
value
]);
}
});
}
const
intermediate
=
intermediateGraphOption
(
intermediateArr
,
intermediateId
);
// re-render
this
.
setState
({
intermediateKeys
:
[
value
],
intermediateOption
:
intermediate
});
}
const
intermediate
=
intermediateGraphOption
(
intermediateArr
,
intermediateId
);
// re-render
this
.
setState
({
intermediateOption
:
intermediate
});
}
hideIntermediateModal
=
():
void
=>
{
...
...
@@ -239,81 +307,20 @@ class TableList extends React.Component<TableListProps, TableListState> {
}
hideShowColumnModal
=
():
void
=>
{
this
.
setState
({
isShowColumn
:
false
});
this
.
setState
(()
=>
({
isShowColumn
:
false
}));
}
// click add column btn, just show the modal of addcolumn
addColumn
=
():
void
=>
{
// show user select check button
this
.
setState
({
isShowColumn
:
true
});
}
// checkbox for coloumn
selectedColumn
=
(
checkedValues
:
Array
<
string
>
):
void
=>
{
// 9: because have nine common column,
// [Intermediate count, Start Time, End Time] is hidden by default
let
count
=
9
;
const
want
:
Array
<
object
>
=
[];
const
finalKeys
:
Array
<
string
>
=
[];
const
wantResult
:
Array
<
string
>
=
[];
Object
.
keys
(
checkedValues
).
map
(
m
=>
{
switch
(
checkedValues
[
m
])
{
case
'
Trial No.
'
:
case
'
ID
'
:
case
'
Start Time
'
:
case
'
End Time
'
:
case
'
Duration
'
:
case
'
Status
'
:
case
'
Operation
'
:
case
'
Default
'
:
case
'
Intermediate result
'
:
break
;
default
:
finalKeys
.
push
(
checkedValues
[
m
]);
}
});
Object
.
keys
(
finalKeys
).
map
(
n
=>
{
want
.
push
({
name
:
finalKeys
[
n
],
index
:
count
++
});
});
Object
.
keys
(
checkedValues
).
map
(
item
=>
{
const
temp
=
checkedValues
[
item
];
Object
.
keys
(
COLUMN_INDEX
).
map
(
key
=>
{
const
index
=
COLUMN_INDEX
[
key
];
if
(
index
.
name
===
temp
)
{
want
.
push
(
index
);
}
});
});
want
.
sort
((
a
:
ColumnIndex
,
b
:
ColumnIndex
)
=>
{
return
a
.
index
-
b
.
index
;
});
Object
.
keys
(
want
).
map
(
i
=>
{
wantResult
.
push
(
want
[
i
].
name
);
});
this
.
props
.
changeColumn
(
wantResult
);
}
openRow
=
(
record
:
TableRecord
):
any
=>
{
return
(
<
OpenRow
trialId
=
{
record
.
id
}
/>
);
this
.
setState
(()
=>
({
isShowColumn
:
true
}));
}
fillSelectedRowsTostate
=
(
selected
:
number
[]
|
string
[],
selectedRows
:
Array
<
TableRecord
>
):
void
=>
{
this
.
setState
({
selectRows
:
selectedRows
,
selectedRowKeys
:
selected
});
}
// open Compare-modal
compareBtn
=
():
void
=>
{
...
...
@@ -324,6 +331,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
this
.
setState
({
isShowCompareModal
:
true
});
}
}
// close Compare-modal
hideCompareModal
=
():
void
=>
{
// close modal. clear select rows data, clear selected track
...
...
@@ -331,178 +339,181 @@ class TableList extends React.Component<TableListProps, TableListState> {
}
// open customized trial modal
setCustomizedTrial
=
(
trialId
:
string
):
void
=>
{
private
setCustomizedTrial
=
(
trialId
:
string
,
event
:
React
.
SyntheticEvent
<
EventTarget
>
):
void
=>
{
event
.
preventDefault
();
event
.
stopPropagation
();
this
.
setState
({
isShowCustomizedModal
:
true
,
copyTrialId
:
trialId
});
}
closeCustomizedTrial
=
():
void
=>
{
private
closeCustomizedTrial
=
():
void
=>
{
this
.
setState
({
isShowCustomizedModal
:
false
,
copyTrialId
:
''
});
}
render
():
React
.
ReactNode
{
const
{
pageSize
,
columnList
}
=
this
.
props
;
const
tableSource
:
Array
<
TableRecord
>
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
props
.
tableSource
));
const
{
intermediateOption
,
modalVisible
,
isShowColumn
,
selectRows
,
isShowCompareModal
,
selectedRowKeys
,
intermediateOtherKeys
,
isShowCustomizedModal
,
copyTrialId
}
=
this
.
state
;
const
rowSelection
=
{
selectedRowKeys
:
selectedRowKeys
,
onChange
:
(
selected
:
string
[]
|
number
[],
selectedRows
:
Array
<
TableRecord
>
):
void
=>
{
this
.
fillSelectedRowsTostate
(
selected
,
selectedRows
);
}
};
// [supportCustomizedTrial: true]
const
supportCustomizedTrial
=
(
EXPERIMENT
.
multiPhase
===
true
)
?
false
:
true
;
const
disabledAddCustomizedTrial
=
[
'
DONE
'
,
'
ERROR
'
,
'
STOPPED
'
].
includes
(
EXPERIMENT
.
status
);
let
showTitle
=
COLUMNPro
;
const
showColumn
:
Array
<
object
>
=
[];
private
onWindowResize
=
():
void
=>
{
this
.
setState
(()
=>
({
modalIntermediateHeight
:
window
.
innerHeight
,
modalIntermediateWidth
:
window
.
innerWidth
}));
}
private
onRenderRow
:
IDetailsListProps
[
'
onRenderRow
'
]
=
props
=>
{
if
(
props
)
{
return
<
Details
detailsProps
=
{
props
}
/>;
}
return
null
;
};
private
getSelectedRows
=
new
Selection
({
onSelectionChanged
:
():
void
=>
{
this
.
setState
(()
=>
({
selectRows
:
this
.
getSelectedRows
.
getSelection
()
}));
}
});
// trial parameters & dict final keys & Trial No. Id ...
private
getAllColumnKeys
=
():
string
[]
=>
{
const
tableSource
:
Array
<
TableRecord
>
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
props
.
tableSource
));
// parameter as table column
const
parameterStr
:
Array
<
string
>
=
[];
const
parameterStr
:
string
[]
=
[];
if
(
tableSource
.
length
>
0
)
{
const
trialMess
=
TRIALS
.
getTrial
(
tableSource
[
0
].
id
);
const
trial
=
trialMess
.
description
.
parameters
;
const
parameterColumn
:
Array
<
string
>
=
Object
.
keys
(
trial
);
const
parameterColumn
:
string
[]
=
Object
.
keys
(
trial
);
parameterColumn
.
forEach
(
value
=>
{
parameterStr
.
push
(
`
${
value
}
(search space)`
);
});
}
showTitle
=
COLUMNPro
.
concat
(
parameterStr
);
let
allColumnList
=
COLUMNPro
;
// eslint-disable-line @typescript-eslint/no-unused-vars
allColumnList
=
COLUMNPro
.
concat
(
parameterStr
);
// only succeed trials have final keys
if
(
tableSource
.
filter
(
record
=>
record
.
status
===
'
SUCCEEDED
'
).
length
>=
1
)
{
const
temp
=
tableSource
.
filter
(
record
=>
record
.
status
===
'
SUCCEEDED
'
)[
0
].
accuracy
;
if
(
temp
!==
undefined
&&
typeof
temp
===
'
object
'
)
{
// concat default column and finalkeys
const
item
=
Object
.
keys
(
temp
);
// item: ['default', 'other-keys', 'maybe loss']
if
(
item
.
length
>
1
)
{
const
want
:
Array
<
string
>
=
[];
item
.
forEach
(
value
=>
{
if
(
value
!==
'
default
'
)
{
want
.
push
(
value
);
}
});
showTitle
=
COLUMNPro
.
concat
(
want
);
if
(
!
isNaN
(
temp
))
{
// concat default column and finalkeys
const
item
=
Object
.
keys
(
temp
);
// item: ['default', 'other-keys', 'maybe loss']
if
(
item
.
length
>
1
)
{
const
want
:
string
[]
=
[];
item
.
forEach
(
value
=>
{
if
(
value
!==
'
default
'
)
{
want
.
push
(
value
);
}
});
allColumnList
=
COLUMNPro
.
concat
(
want
);
}
}
}
}
return
allColumnList
;
}
// get IColumn[]
// when user click [Add Column] need to use the function
private
initTableColumnList
=
(
columnList
:
string
[]):
IColumn
[]
=>
{
// const { columnList } = this.props;
// [supportCustomizedTrial: true]
const
supportCustomizedTrial
=
(
EXPERIMENT
.
multiPhase
===
true
)
?
false
:
true
;
const
disabledAddCustomizedTrial
=
[
'
DONE
'
,
'
ERROR
'
,
'
STOPPED
'
].
includes
(
EXPERIMENT
.
status
);
const
showColumn
:
IColumn
[]
=
[];
for
(
const
item
of
columnList
)
{
const
paraColumn
=
item
.
match
(
/
\(
search space
\)
$/
);
let
cc
;
let
result
;
if
(
paraColumn
!==
null
)
{
cc
=
paraColumn
.
input
;
result
=
paraColumn
.
input
;
}
switch
(
item
)
{
case
'
Trial No.
'
:
showColumn
.
push
(
SequenceIdColumnConfig
);
showColumn
.
push
(
this
.
SequenceIdColumnConfig
);
break
;
case
'
ID
'
:
showColumn
.
push
(
IdColumnConfig
);
showColumn
.
push
(
this
.
IdColumnConfig
);
break
;
case
'
Start Time
'
:
showColumn
.
push
(
StartTimeColumnConfig
);
showColumn
.
push
(
this
.
StartTimeColumnConfig
);
break
;
case
'
End Time
'
:
showColumn
.
push
(
EndTimeColumnConfig
);
showColumn
.
push
(
this
.
EndTimeColumnConfig
);
break
;
case
'
Duration
'
:
showColumn
.
push
(
DurationColumnConfig
);
showColumn
.
push
(
this
.
DurationColumnConfig
);
break
;
case
'
Status
'
:
showColumn
.
push
(
StatusColumnConfig
);
showColumn
.
push
(
this
.
StatusColumnConfig
);
break
;
case
'
Intermediate result
'
:
showColumn
.
push
(
IntermediateCountColumnConfig
);
showColumn
.
push
(
this
.
IntermediateCountColumnConfig
);
break
;
case
'
Default
'
:
showColumn
.
push
(
AccuracyColumnConfig
);
showColumn
.
push
(
this
.
AccuracyColumnConfig
);
break
;
case
'
Operation
'
:
showColumn
.
push
({
title
:
'
Operation
'
,
dataIndex
:
'
operation
'
,
name
:
'
Operation
'
,
key
:
'
operation
'
,
render
:
(
text
:
string
,
record
:
TableRecord
)
=>
{
fieldName
:
'
operation
'
,
minWidth
:
160
,
maxWidth
:
200
,
isResizable
:
true
,
className
:
'
detail-table
'
,
onRender
:
(
record
:
any
)
=>
{
const
trialStatus
=
record
.
status
;
// could kill a job when its status is RUNNING or UNKNOWN
const
flag
:
boolean
=
(
trialStatus
===
'
RUNNING
'
||
trialStatus
===
'
UNKNOWN
'
)
?
false
:
true
;
return
(
<
Row
id
=
"detail-button"
>
<
Stack
className
=
"detail-button"
horizontal
>
{
/* see intermediate result graph */
}
<
Button
type
=
"primary"
className
=
"common-style"
onClick
=
{
this
.
showIntermediateModal
.
bind
(
this
,
record
.
id
)
}
<
PrimaryButton
className
=
"detail-button-operation"
title
=
"Intermediate"
onClick
=
{
this
.
showIntermediateModal
.
bind
(
this
,
record
.
id
)
}
>
<
Icon
type
=
"l
ine
-c
hart
"
/>
</
Button
>
{
L
ine
C
hart
}
</
Primary
Button
>
{
/* kill job */
}
{
flag
?
<
Button
type
=
"default"
disabled
=
{
true
}
className
=
"margin-mediate special"
title
=
"kill"
>
<
Icon
type
=
"stop"
/>
</
Button
>
<
PrimaryButton
className
=
"detail-button-operation"
disabled
=
{
true
}
title
=
"kill"
>
{
blocked
}
</
PrimaryButton
>
:
<
Popconfirm
title
=
"Are you sure to cancel this trial?"
okText
=
"Yes"
cancelText
=
"No"
onConfirm
=
{
killJob
.
bind
(
this
,
record
.
key
,
record
.
id
,
record
.
status
)
}
>
<
Button
type
=
"default"
disabled
=
{
false
}
className
=
"margin-mediate special"
title
=
"kill"
>
<
Icon
type
=
"stop"
/>
</
Button
>
</
Popconfirm
>
<
KillJob
trial
=
{
record
}
/>
}
{
/* Add a new trial-customized trial */
}
{
supportCustomizedTrial
?
<
Button
type
=
"primary"
className
=
"common-style"
disabled
=
{
disabledAddCustomizedTrial
}
onClick
=
{
this
.
setCustomizedTrial
.
bind
(
this
,
record
.
id
)
}
<
PrimaryButton
className
=
"detail-button-operation"
title
=
"Customized trial"
onClick
=
{
this
.
setCustomizedTrial
.
bind
(
this
,
record
.
id
)
}
disabled
=
{
disabledAddCustomizedTrial
}
>
<
Icon
type
=
"copy"
/>
</
Button
>
{
copy
}
</
Primary
Button
>
:
null
}
</
Row
>
</
Stack
>
);
},
});
break
;
case
(
cc
):
case
(
result
):
// remove SEARCH_SPACE title
// const realItem = item.replace(' (search space)', '');
showColumn
.
push
({
title
:
item
.
replace
(
'
(search space)
'
,
''
),
dataIndex
:
item
,
name
:
item
.
replace
(
'
(search space)
'
,
''
),
key
:
item
,
render
:
(
text
:
string
,
record
:
TableRecord
)
=>
{
fieldName
:
item
,
minWidth
:
150
,
onRender
:
(
record
:
TableRecord
)
=>
{
const
eachTrial
=
TRIALS
.
getTrial
(
record
.
id
);
return
(
<
span
>
{
eachTrial
.
description
.
parameters
[
item
.
replace
(
'
(search space)
'
,
''
)]
}
</
span
>
...
...
@@ -515,88 +526,110 @@ class TableList extends React.Component<TableListProps, TableListState> {
alert
(
'
Unexpected column type
'
);
}
}
return
showColumn
;
}
componentDidMount
():
void
{
window
.
addEventListener
(
'
resize
'
,
this
.
onWindowResize
);
}
UNSAFE_componentWillReceiveProps
(
nextProps
:
TableListProps
):
void
{
const
{
columnList
}
=
nextProps
;
this
.
setState
({
tableColumns
:
this
.
initTableColumnList
(
columnList
)
});
}
render
():
React
.
ReactNode
{
const
{
intermediateKeys
,
modalIntermediateWidth
,
modalIntermediateHeight
,
tableColumns
,
allColumnList
,
isShowColumn
,
modalVisible
,
selectRows
,
isShowCompareModal
,
intermediateOtherKeys
,
isShowCustomizedModal
,
copyTrialId
,
intermediateOption
}
=
this
.
state
;
const
{
columnList
}
=
this
.
props
;
const
tableSource
:
Array
<
TableRecord
>
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
state
.
tableSourceForSort
));
return
(
<
Row
className
=
"tableList"
>
<
Stack
>
<
div
id
=
"tableList"
>
<
Table
ref
=
{
(
table
:
Table
<
TableRecord
>
|
null
):
any
=>
this
.
tables
=
table
}
columns
=
{
showColumn
}
rowSelection
=
{
rowSelection
}
expandedRowRender
=
{
this
.
openRow
}
dataSource
=
{
tableSource
}
c
la
ssName
=
"commonTableStyle"
s
croll
=
{
{
x
:
'
max-content
'
}
}
pagination
=
{
pageSize
>
0
?
{
pageSize
}
:
false
}
<
DetailsList
columns
=
{
tableColumns
}
items
=
{
tableSource
}
setKey
=
"set"
compact
=
{
true
}
onRenderRow
=
{
this
.
onRenderRow
}
la
youtMode
=
{
DetailsListLayoutMode
.
justified
}
s
electionMode
=
{
SelectionMode
.
multiple
}
selection
=
{
this
.
getSelectedRows
}
/>
{
/* Intermediate Result Modal */
}
<
Modal
title
=
"Intermediate result"
visible
=
{
modalVisible
}
onCancel
=
{
this
.
hideIntermediateModal
}
footer
=
{
null
}
destroyOnClose
=
{
true
}
width
=
"80%"
>
{
intermediateOtherKeys
.
length
>
1
?
<
Row
className
=
"selectKeys"
>
<
Select
className
=
"select"
defaultValue
=
"default"
onSelect
=
{
this
.
selectOtherKeys
}
>
{
Object
.
keys
(
intermediateOtherKeys
).
map
(
item
=>
{
const
keys
=
intermediateOtherKeys
[
item
];
return
<
Option
value
=
{
keys
}
key
=
{
item
}
>
{
keys
}
</
Option
>;
})
}
</
Select
>
</
Row
>
:
<
div
/>
}
<
ReactEcharts
option
=
{
intermediateOption
}
style
=
{
{
width
:
'
100%
'
,
height
:
0.7
*
window
.
innerHeight
}
}
theme
=
"my_theme"
/>
</
Modal
>
</
div
>
{
/*
Add Column
Modal */
}
{
/*
Intermediate Result
Modal */
}
<
Modal
title
=
"Table Title"
visible
=
{
isShowColumn
}
onCancel
=
{
this
.
hideShowColumnModal
}
footer
=
{
null
}
destroyOnClose
=
{
true
}
width
=
"40%"
isOpen
=
{
modalVisible
}
onDismiss
=
{
this
.
hideIntermediateModal
}
containerClassName
=
{
contentStyles
.
container
}
>
<
CheckboxGroup
options
=
{
showTitle
}
defaultValue
=
{
columnList
}
// defaultValue={columnSelected}
onChange
=
{
this
.
selectedColumn
}
className
=
"titleColumn"
<
div
className
=
{
contentStyles
.
header
}
>
<
span
>
Intermediate result
</
span
>
<
IconButton
styles
=
{
iconButtonStyles
}
iconProps
=
{
{
iconName
:
'
Cancel
'
}
}
ariaLabel
=
"Close popup modal"
onClick
=
{
this
.
hideIntermediateModal
as
any
}
/>
</
div
>
{
intermediateOtherKeys
.
length
>
1
?
<
Stack
className
=
"selectKeys"
styles
=
{
{
root
:
{
width
:
800
}
}
}
>
<
Dropdown
className
=
"select"
selectedKeys
=
{
intermediateKeys
}
onChange
=
{
this
.
selectOtherKeys
}
options
=
{
intermediateOtherKeys
.
map
((
key
,
item
)
=>
{
return
{
key
:
key
,
text
:
intermediateOtherKeys
[
item
]
};
})
}
styles
=
{
{
dropdown
:
{
width
:
300
}
}
}
/>
</
Stack
>
:
null
}
<
ReactEcharts
option
=
{
intermediateOption
}
style
=
{
{
width
:
0.5
*
modalIntermediateWidth
,
height
:
0.7
*
modalIntermediateHeight
,
padding
:
20
}
}
theme
=
"my_theme"
/>
</
Modal
>
{
/* Add Column Modal */
}
{
isShowColumn
&&
<
ChangeColumnComponent
hideShowColumnDialog
=
{
this
.
hideShowColumnModal
}
isHideDialog
=
{
!
isShowColumn
}
showColumn
=
{
allColumnList
}
selectedColumn
=
{
columnList
}
changeColumn
=
{
this
.
props
.
changeColumn
}
/>
}
{
/* compare trials based message */
}
<
Compare
compare
Row
s
=
{
selectRows
}
visible
=
{
isShowCompareModal
}
cancelFunc
=
{
this
.
hideCompareModal
}
/>
{
isShowCompareModal
&&
<
Compare
compare
Stack
s
=
{
selectRows
}
cancelFunc
=
{
this
.
hideCompareModal
}
/>
}
{
/* clone trial parameters and could submit a customized trial */
}
<
Customize
visible
=
{
isShowCustomizedModal
}
copyTrialId
=
{
copyTrialId
}
closeCustomizeModal
=
{
this
.
closeCustomizedTrial
}
/>
</
Row
>
</
Stack
>
);
}
}
export
default
TableList
;
export
default
TableList
;
\ No newline at end of file
Prev
1
2
3
4
5
Next
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