Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
nni
Commits
aa316742
Unverified
Commit
aa316742
authored
Feb 21, 2020
by
SparkSnail
Committed by
GitHub
Feb 21, 2020
Browse files
Merge pull request #233 from microsoft/master
merge master
parents
3fe117f0
24fa4619
Changes
285
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
834 additions
and
691 deletions
+834
-691
src/webui/src/components/TrialsDetail.tsx
src/webui/src/components/TrialsDetail.tsx
+91
-103
src/webui/src/components/overview/Accuracy.tsx
src/webui/src/components/overview/Accuracy.tsx
+4
-5
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
No files found.
src/webui/src/components/TrialsDetail.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Row
,
Col
,
Tabs
,
Select
,
Button
,
Icon
}
from
'
antd
'
;
import
{
const
Option
=
Select
.
Option
;
Stack
,
StackItem
,
Pivot
,
PivotItem
,
Dropdown
,
IDropdownOption
,
DefaultButton
}
from
'
office-ui-fabric-react
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../static/datamodel
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../static/datamodel
'
;
import
{
Trial
}
from
'
../static/model/trial
'
;
import
{
Trial
}
from
'
../static/model/trial
'
;
import
{
tableListIcon
}
from
'
./Buttons/Icon
'
;
import
DefaultPoint
from
'
./trial-detail/DefaultMetricPoint
'
;
import
DefaultPoint
from
'
./trial-detail/DefaultMetricPoint
'
;
import
Duration
from
'
./trial-detail/Duration
'
;
import
Duration
from
'
./trial-detail/Duration
'
;
import
Title1
from
'
./overview/Title1
'
;
import
Para
from
'
./trial-detail/Para
'
;
import
Para
from
'
./trial-detail/Para
'
;
import
Intermediate
from
'
./trial-detail/Intermediate
'
;
import
Intermediate
from
'
./trial-detail/Intermediate
'
;
import
TableList
from
'
./trial-detail/TableList
'
;
import
TableList
from
'
./trial-detail/TableList
'
;
const
TabPane
=
Tabs
.
TabPane
;
import
'
../static/style/trialsDetail.scss
'
;
import
'
../static/style/trialsDetail.scss
'
;
import
'
../static/style/search.scss
'
;
import
'
../static/style/search.scss
'
;
...
@@ -21,8 +21,8 @@ interface TrialDetailState {
...
@@ -21,8 +21,8 @@ interface TrialDetailState {
}
}
interface
TrialsDetailProps
{
interface
TrialsDetailProps
{
columnList
:
Array
<
string
>
;
columnList
:
string
[]
;
changeColumn
:
(
val
:
Array
<
string
>
)
=>
void
;
changeColumn
:
(
val
:
string
[]
)
=>
void
;
experimentUpdateBroacast
:
number
;
experimentUpdateBroacast
:
number
;
trialsUpdateBroadcast
:
number
;
trialsUpdateBroadcast
:
number
;
}
}
...
@@ -32,59 +32,40 @@ class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState>
...
@@ -32,59 +32,40 @@ class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState>
public
interAccuracy
=
0
;
public
interAccuracy
=
0
;
public
interAllTableList
=
2
;
public
interAllTableList
=
2
;
public
tableList
:
TableList
|
null
;
public
tableList
!
:
TableList
|
null
;
public
searchInput
:
HTMLInputElement
|
null
;
public
searchInput
!
:
HTMLInputElement
|
null
;
private
titleOfacc
=
(
<
Title1
text
=
"Default metric"
icon
=
"3.png"
/>
);
private
titleOfhyper
=
(
<
Title1
text
=
"Hyper-parameter"
icon
=
"1.png"
/>
);
private
titleOfDuration
=
(
<
Title1
text
=
"Trial duration"
icon
=
"2.png"
/>
);
private
titleOfIntermediate
=
(
<
div
className
=
"panelTitle"
>
<
Icon
type
=
"line-chart"
/>
<
span
>
Intermediate result
</
span
>
</
div
>
);
constructor
(
props
:
TrialsDetailProps
)
{
constructor
(
props
:
TrialsDetailProps
)
{
super
(
props
);
super
(
props
);
this
.
state
=
{
this
.
state
=
{
tablePageSize
:
20
,
tablePageSize
:
20
,
whichGraph
:
'
1
'
,
whichGraph
:
'
1
'
,
searchType
:
'
i
d
'
,
searchType
:
'
I
d
'
,
// eslint-disable-next-line @typescript-eslint/
explicit-function-return-type, @typescript-eslint/no-unused-vars
// eslint-disable-next-line @typescript-eslint/
no-unused-vars, @typescript-eslint/explicit-function-return-type
searchFilter
:
trial
=>
true
searchFilter
:
trial
=>
true
};
};
}
}
// search a trial by trial No.
&
trial id
// search a trial by trial No.
|
trial id
| Parameters | Status
searchTrial
=
(
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
):
void
=>
{
searchTrial
=
(
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
):
void
=>
{
const
targetValue
=
event
.
target
.
value
;
const
targetValue
=
event
.
target
.
value
;
// eslint-disable-next-line
@typescript-eslint/explicit-function-return-type,
@typescript-eslint/no-unused-vars
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let
filter
=
(
trial
:
Trial
)
=>
true
;
let
filter
=
(
trial
:
Trial
)
:
boolean
=>
true
;
if
(
!
targetValue
.
trim
())
{
if
(
!
targetValue
.
trim
())
{
this
.
setState
({
searchFilter
:
filter
});
this
.
setState
({
searchFilter
:
filter
});
return
;
return
;
}
}
switch
(
this
.
state
.
searchType
)
{
switch
(
this
.
state
.
searchType
)
{
case
'
i
d
'
:
case
'
I
d
'
:
filter
=
(
trial
):
boolean
=>
trial
.
info
.
id
.
toUpperCase
().
includes
(
targetValue
.
toUpperCase
());
filter
=
(
trial
):
boolean
=>
trial
.
info
.
id
.
toUpperCase
().
includes
(
targetValue
.
toUpperCase
());
break
;
break
;
case
'
Trial No.
'
:
case
'
Trial No.
'
:
filter
=
(
trial
):
boolean
=>
trial
.
info
.
sequenceId
.
toString
()
===
targetValue
;
filter
=
(
trial
):
boolean
=>
trial
.
info
.
sequenceId
.
toString
()
===
targetValue
;
break
;
break
;
case
'
s
tatus
'
:
case
'
S
tatus
'
:
filter
=
(
trial
):
boolean
=>
trial
.
info
.
status
.
toUpperCase
().
includes
(
targetValue
.
toUpperCase
());
filter
=
(
trial
):
boolean
=>
trial
.
info
.
status
.
toUpperCase
().
includes
(
targetValue
.
toUpperCase
());
break
;
break
;
case
'
p
arameters
'
:
case
'
P
arameters
'
:
// TODO: support filters like `x: 2` (instead of `"x": 2`)
// TODO: support filters like `x: 2` (instead of `"x": 2`)
filter
=
(
trial
):
boolean
=>
JSON
.
stringify
(
trial
.
info
.
hyperParameters
,
null
,
4
).
includes
(
targetValue
);
filter
=
(
trial
):
boolean
=>
JSON
.
stringify
(
trial
.
info
.
hyperParameters
,
null
,
4
).
includes
(
targetValue
);
break
;
break
;
...
@@ -94,112 +75,119 @@ class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState>
...
@@ -94,112 +75,119 @@ class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState>
this
.
setState
({
searchFilter
:
filter
});
this
.
setState
({
searchFilter
:
filter
});
}
}
handleTablePageSizeSelect
=
(
value
:
string
):
void
=>
{
handleTablePageSizeSelect
=
(
event
:
React
.
FormEvent
<
HTMLDivElement
>
,
item
:
IDropdownOption
|
undefined
):
void
=>
{
this
.
setState
({
tablePageSize
:
value
===
'
all
'
?
-
1
:
parseInt
(
value
,
10
)
});
if
(
item
!==
undefined
)
{
this
.
setState
({
tablePageSize
:
item
.
text
===
'
all
'
?
-
1
:
parseInt
(
item
.
text
,
10
)
});
}
}
}
handleWhichTabs
=
(
activeKey
:
string
):
void
=>
{
handleWhichTabs
=
(
activeKey
:
string
):
void
=>
{
this
.
setState
({
whichGraph
:
activeKey
});
this
.
setState
({
whichGraph
:
activeKey
});
}
}
updateSearchFilterType
=
(
value
:
string
):
void
=>
{
updateSearchFilterType
=
(
event
:
React
.
FormEvent
<
HTMLDivElement
>
,
item
:
IDropdownOption
|
undefined
):
void
=>
{
// clear input value and re-render table
// clear input value and re-render table
if
(
this
.
searchInput
!==
null
)
{
if
(
item
!==
undefined
)
{
this
.
searchInput
.
value
=
''
;
if
(
this
.
searchInput
!==
null
)
{
this
.
searchInput
.
value
=
''
;
}
this
.
setState
(()
=>
({
searchType
:
item
.
text
}));
}
}
this
.
setState
({
searchType
:
value
});
}
}
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
tablePageSize
,
whichGraph
}
=
this
.
state
;
const
{
tablePageSize
,
whichGraph
,
searchType
}
=
this
.
state
;
const
{
columnList
,
changeColumn
}
=
this
.
props
;
const
{
columnList
,
changeColumn
}
=
this
.
props
;
const
source
=
TRIALS
.
filter
(
this
.
state
.
searchFilter
);
const
source
=
TRIALS
.
filter
(
this
.
state
.
searchFilter
);
const
trialIds
=
TRIALS
.
filter
(
this
.
state
.
searchFilter
).
map
(
trial
=>
trial
.
id
);
const
trialIds
=
TRIALS
.
filter
(
this
.
state
.
searchFilter
).
map
(
trial
=>
trial
.
id
);
const
searchOptions
=
[
{
key
:
'
Id
'
,
text
:
'
Id
'
},
{
key
:
'
Trial No.
'
,
text
:
'
Trial No.
'
},
{
key
:
'
Status
'
,
text
:
'
Status
'
},
{
key
:
'
Parameters
'
,
text
:
'
Parameters
'
},
];
return
(
return
(
<
div
>
<
div
>
<
div
className
=
"trial"
id
=
"tabsty"
>
<
div
className
=
"trial"
id
=
"tabsty"
>
<
Tabs
type
=
"card"
onChange
=
{
this
.
handleWhichTabs
}
>
<
Pivot
defaultSelectedKey
=
{
"
0
"
}
className
=
"detial-title"
>
<
TabPane
tab
=
{
this
.
titleOfacc
}
key
=
"1"
>
{
/* <PivotItem tab={this.titleOfacc} key="1"> doesn't work*/
}
<
Row
className
=
"graph"
>
<
PivotItem
headerText
=
"Default metric"
itemIcon
=
"HomeGroup"
key
=
"1"
>
<
Stack
className
=
"graph"
>
<
DefaultPoint
<
DefaultPoint
trialIds
=
{
trialIds
}
trialIds
=
{
trialIds
}
visible
=
{
whichGraph
===
'
1
'
}
visible
=
{
whichGraph
===
'
1
'
}
trialsUpdateBroadcast
=
{
this
.
props
.
trialsUpdateBroadcast
}
trialsUpdateBroadcast
=
{
this
.
props
.
trialsUpdateBroadcast
}
/>
/>
</
Row
>
</
Stack
>
</
TabPane
>
</
PivotItem
>
<
TabPane
tab
=
{
this
.
titleOfhyper
}
key
=
"2"
>
{
/* <PivotItem tab={this.titleOfhyper} key="2"> */
}
<
Row
className
=
"graph"
>
<
PivotItem
headerText
=
"Hyper-parameter"
itemIcon
=
"Equalizer"
key
=
"2"
>
<
Stack
className
=
"graph"
>
<
Para
<
Para
dataSource
=
{
source
}
dataSource
=
{
source
}
expSearchSpace
=
{
JSON
.
stringify
(
EXPERIMENT
.
searchSpace
)
}
expSearchSpace
=
{
JSON
.
stringify
(
EXPERIMENT
.
searchSpace
)
}
whichGraph
=
{
whichGraph
}
whichGraph
=
{
whichGraph
}
/>
/>
</
Row
>
</
Stack
>
</
TabPane
>
</
PivotItem
>
<
TabPane
tab
=
{
this
.
titleOfDuration
}
key
=
"3"
>
{
/* <PivotItem tab={this.titleOfDuration} key="3"> */
}
<
PivotItem
headerText
=
"Duration"
itemIcon
=
"BarChartHorizontal"
key
=
"3"
>
<
Duration
source
=
{
source
}
whichGraph
=
{
whichGraph
}
/>
<
Duration
source
=
{
source
}
whichGraph
=
{
whichGraph
}
/>
</
TabPane
>
</
PivotItem
>
<
TabPane
tab
=
{
this
.
titleOfIntermediate
}
key
=
"4"
>
{
/* <PivotItem tab={this.titleOfIntermediate} key="4"> */
}
<
PivotItem
headerText
=
"Intermediate result"
itemIcon
=
"StackedLineChart"
key
=
"4"
>
{
/* *why this graph has small footprint? */
}
<
Intermediate
source
=
{
source
}
whichGraph
=
{
whichGraph
}
/>
<
Intermediate
source
=
{
source
}
whichGraph
=
{
whichGraph
}
/>
</
TabPane
>
</
PivotItem
>
</
Tabs
>
</
Pivot
>
</
div
>
</
div
>
{
/* trial table list */
}
{
/* trial table list */
}
<
Title1
text
=
"Trial jobs"
icon
=
"6.png"
/>
<
Stack
horizontal
className
=
"panelTitle"
>
<
Row
className
=
"allList"
>
<
span
style
=
{
{
marginRight
:
12
}
}
>
{
tableListIcon
}
</
span
>
<
Col
span
=
{
10
}
>
<
span
>
Trial jobs
</
span
>
<
span
>
Show
</
span
>
</
Stack
>
<
Select
<
Stack
horizontal
className
=
"allList"
>
className
=
"entry"
<
StackItem
grow
=
{
50
}
>
onSelect
=
{
this
.
handleTablePageSizeSelect
}
<
DefaultButton
defaultValue
=
"20"
text
=
"Compare"
>
className
=
"allList-compare"
<
Option
value
=
"20"
>
20
</
Option
>
<
Option
value
=
"50"
>
50
</
Option
>
<
Option
value
=
"100"
>
100
</
Option
>
<
Option
value
=
"all"
>
All
</
Option
>
</
Select
>
<
span
>
entries
</
span
>
</
Col
>
<
Col
span
=
{
14
}
className
=
"right"
>
<
Button
className
=
"common"
onClick
=
{
():
void
=>
{
if
(
this
.
tableList
)
{
this
.
tableList
.
addColumn
();
}}
}
>
Add column
</
Button
>
<
Button
className
=
"mediateBtn common"
// use child-component tableList's function, the function is in child-component.
// use child-component tableList's function, the function is in child-component.
onClick
=
{
():
void
=>
{
if
(
this
.
tableList
)
{
this
.
tableList
.
compareBtn
();
}}
}
onClick
=
{
():
void
=>
{
if
(
this
.
tableList
)
{
this
.
tableList
.
compareBtn
();
}
}
}
>
Compare
</
Button
>
<
Select
defaultValue
=
"id"
className
=
"filter"
onSelect
=
{
this
.
updateSearchFilterType
}
>
<
Option
value
=
"id"
>
Id
</
Option
>
<
Option
value
=
"Trial No."
>
Trial No.
</
Option
>
<
Option
value
=
"status"
>
Status
</
Option
>
<
Option
value
=
"parameters"
>
Parameters
</
Option
>
</
Select
>
<
input
type
=
"text"
className
=
"search-input"
placeholder
=
{
`Search by
${
this
.
state
.
searchType
}
`
}
onChange
=
{
this
.
searchTrial
}
style
=
{
{
width
:
230
}
}
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
ref
=
{
text
=>
(
this
.
searchInput
)
=
text
}
/>
/>
</
Col
>
</
StackItem
>
</
Row
>
<
StackItem
grow
=
{
50
}
>
<
Stack
horizontal
horizontalAlign
=
"end"
className
=
"allList"
>
<
DefaultButton
className
=
"allList-button-gap"
text
=
"Add column"
onClick
=
{
():
void
=>
{
if
(
this
.
tableList
)
{
this
.
tableList
.
addColumn
();
}
}
}
/>
<
Dropdown
selectedKey
=
{
searchType
}
options
=
{
searchOptions
}
onChange
=
{
this
.
updateSearchFilterType
}
styles
=
{
{
root
:
{
width
:
150
}
}
}
/>
<
input
type
=
"text"
className
=
"allList-search-input"
placeholder
=
{
`Search by
${
this
.
state
.
searchType
}
`
}
onChange
=
{
this
.
searchTrial
}
style
=
{
{
width
:
230
}
}
ref
=
{
(
text
):
any
=>
(
this
.
searchInput
)
=
text
}
/>
</
Stack
>
</
StackItem
>
</
Stack
>
<
TableList
<
TableList
pageSize
=
{
tablePageSize
}
pageSize
=
{
tablePageSize
}
tableSource
=
{
source
.
map
(
trial
=>
trial
.
tableRecord
)
}
tableSource
=
{
source
.
map
(
trial
=>
trial
.
tableRecord
)
}
columnList
=
{
columnList
}
columnList
=
{
columnList
}
changeColumn
=
{
changeColumn
}
changeColumn
=
{
changeColumn
}
trialsUpdateBroadcast
=
{
this
.
props
.
trialsUpdateBroadcast
}
trialsUpdateBroadcast
=
{
this
.
props
.
trialsUpdateBroadcast
}
ref
=
{
(
tabList
)
=>
this
.
tableList
=
tabList
}
// eslint-disable-line @typescript-eslint/explicit-function-return-type
// TODO: change any to specific type
ref
=
{
(
tabList
):
any
=>
this
.
tableList
=
tabList
}
/>
/>
</
div
>
</
div
>
);
);
...
...
src/webui/src/components/overview/Accuracy.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
cons
t
echarts
=
require
(
'
echarts/lib/echarts
'
)
;
impor
t
echarts
from
'
echarts/lib/echarts
'
;
echarts
.
registerTheme
(
'
my_theme
'
,
{
echarts
.
registerTheme
(
'
my_theme
'
,
{
color
:
'
#3c8dbc
'
color
:
'
#3c8dbc
'
});
});
require
(
'
echarts/lib/chart/scatter
'
)
;
import
'
echarts/lib/chart/scatter
'
;
require
(
'
echarts/lib/component/tooltip
'
)
;
import
'
echarts/lib/component/tooltip
'
;
require
(
'
echarts/lib/component/title
'
)
;
import
'
echarts/lib/component/title
'
;
interface
AccuracyProps
{
interface
AccuracyProps
{
accuracyData
:
object
;
accuracyData
:
object
;
...
@@ -28,7 +28,6 @@ class Accuracy extends React.Component<AccuracyProps, {}> {
...
@@ -28,7 +28,6 @@ class Accuracy extends React.Component<AccuracyProps, {}> {
<
ReactEcharts
<
ReactEcharts
option
=
{
accuracyData
}
option
=
{
accuracyData
}
style
=
{
{
style
=
{
{
width
:
'
90%
'
,
height
:
height
,
height
:
height
,
margin
:
'
0 auto
'
,
margin
:
'
0 auto
'
,
}
}
}
}
...
...
src/webui/src/components/overview/BasicInfo.tsx
View file @
aa316742
import
{
Col
,
Row
,
Tooltip
}
from
'
antd
'
;
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Stack
,
TooltipHost
,
getId
}
from
'
office-ui-fabric-react
'
;
import
{
EXPERIMENT
}
from
'
../../static/datamodel
'
;
import
{
EXPERIMENT
}
from
'
../../static/datamodel
'
;
import
{
formatTimestamp
}
from
'
../../static/function
'
;
import
{
formatTimestamp
}
from
'
../../static/function
'
;
...
@@ -8,36 +8,48 @@ interface BasicInfoProps {
...
@@ -8,36 +8,48 @@ interface BasicInfoProps {
}
}
class
BasicInfo
extends
React
.
Component
<
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
)
{
constructor
(
props
:
BasicInfoProps
)
{
super
(
props
);
super
(
props
);
}
}
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
return
(
return
(
<
Row
className
=
"main"
>
<
Stack
horizontal
horizontalAlign
=
"space-between"
className
=
"main"
>
<
Col
span
=
{
8
}
className
=
"padItem basic"
>
<
Stack
.
Item
grow
=
{
3
}
className
=
"padItem basic"
>
<
p
>
Name
</
p
>
<
p
>
Name
</
p
>
<
div
>
{
EXPERIMENT
.
profile
.
params
.
experimentName
}
</
div
>
<
div
>
{
EXPERIMENT
.
profile
.
params
.
experimentName
}
</
div
>
<
p
>
ID
</
p
>
<
p
>
ID
</
p
>
<
div
>
{
EXPERIMENT
.
profile
.
id
}
</
div
>
<
div
>
{
EXPERIMENT
.
profile
.
id
}
</
div
>
</
Col
>
</
Stack
.
Item
>
<
Col
span
=
{
8
}
className
=
"padItem basic"
>
<
Stack
.
Item
grow
=
{
3
}
className
=
"padItem basic"
>
<
p
>
Start time
</
p
>
<
p
>
Start time
</
p
>
<
div
className
=
"nowrap"
>
{
formatTimestamp
(
EXPERIMENT
.
profile
.
startTime
)
}
</
div
>
<
div
className
=
"nowrap"
>
{
formatTimestamp
(
EXPERIMENT
.
profile
.
startTime
)
}
</
div
>
<
p
>
End time
</
p
>
<
p
>
End time
</
p
>
<
div
className
=
"nowrap"
>
{
formatTimestamp
(
EXPERIMENT
.
profile
.
endTime
)
}
</
div
>
<
div
className
=
"nowrap"
>
{
formatTimestamp
(
EXPERIMENT
.
profile
.
endTime
)
}
</
div
>
</
Col
>
</
Stack
.
Item
>
<
Col
span
=
{
8
}
className
=
"padItem basic"
>
<
Stack
.
Item
className
=
"padItem basic"
>
<
p
>
Log directory
</
p
>
<
p
>
Log directory
</
p
>
<
div
className
=
"nowrap"
>
<
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
'
}
{
EXPERIMENT
.
profile
.
logDir
||
'
unknown
'
}
</
Tooltip
>
</
Tooltip
Host
>
</
div
>
</
div
>
<
p
>
Training platform
</
p
>
<
p
>
Training platform
</
p
>
<
div
className
=
"nowrap"
>
{
EXPERIMENT
.
profile
.
params
.
trainingServicePlatform
}
</
div
>
<
div
className
=
"nowrap"
>
{
EXPERIMENT
.
profile
.
params
.
trainingServicePlatform
}
</
div
>
</
Col
>
</
Stack
.
Item
>
</
Row
>
</
Stack
>
);
);
}
}
}
}
...
...
src/webui/src/components/overview/Details.tsx
0 → 100644
View file @
aa316742
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 @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Button
,
Row
}
from
'
antd
'
;
import
{
Stack
,
Primary
Button
}
from
'
office-ui-fabric-react
'
;
interface
ConcurrencyInputProps
{
interface
ConcurrencyInputProps
{
value
:
number
;
value
:
number
;
...
@@ -36,47 +36,38 @@ class ConcurrencyInput extends React.Component<ConcurrencyInputProps, Concurrenc
...
@@ -36,47 +36,38 @@ class ConcurrencyInput extends React.Component<ConcurrencyInputProps, Concurrenc
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
if
(
this
.
state
.
editting
)
{
if
(
this
.
state
.
editting
)
{
return
(
return
(
<
Row
className
=
"inputBox"
>
<
Stack
horizontal
className
=
"inputBox"
>
<
input
<
input
type
=
"number"
type
=
"number"
className
=
"concurrencyInput"
className
=
"concurrencyInput"
defaultValue
=
{
this
.
props
.
value
.
toString
()
}
defaultValue
=
{
this
.
props
.
value
.
toString
()
}
ref
=
{
this
.
input
}
ref
=
{
this
.
input
}
/>
/>
<
Button
<
PrimaryButton
type
=
"primary"
text
=
"Save"
className
=
"tableButton editStyle"
onClick
=
{
this
.
save
}
onClick
=
{
this
.
save
}
>
/>
Save
<
PrimaryButton
</
Button
>
text
=
"Cancel"
<
Button
type
=
"primary"
onClick
=
{
this
.
cancel
}
style
=
{
{
display
:
'
inline-block
'
,
marginLeft
:
1
}
}
style
=
{
{
display
:
'
inline-block
'
,
marginLeft
:
1
}
}
className
=
"tableButton editStyle"
onClick
=
{
this
.
cancel
}
>
/>
Cancel
</
Stack
>
</
Button
>
</
Row
>
);
);
}
else
{
}
else
{
return
(
return
(
<
Row
className
=
"inputBox"
>
<
Stack
horizontal
className
=
"inputBox"
>
<
input
<
input
type
=
"number"
type
=
"number"
className
=
"concurrencyInput"
className
=
"concurrencyInput"
disabled
=
{
true
}
disabled
=
{
true
}
value
=
{
this
.
props
.
value
}
value
=
{
this
.
props
.
value
}
/>
/>
<
Button
<
PrimaryButton
type
=
"primary"
text
=
"Edit"
className
=
"tableButton editStyle"
onClick
=
{
this
.
edit
}
onClick
=
{
this
.
edit
}
>
/>
Edit
</
Stack
>
</
Button
>
</
Row
>
);
);
}
}
}
}
...
...
src/webui/src/components/overview/Progress.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
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
axios
from
'
axios
'
;
import
{
MANAGER_IP
}
from
'
../../static/const
'
;
import
{
MANAGER_IP
}
from
'
../../static/const
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
convertTime
}
from
'
../../static/function
'
;
import
{
convertTime
}
from
'
../../static/function
'
;
import
ConcurrencyInput
from
'
./NumInput
'
;
import
ConcurrencyInput
from
'
./NumInput
'
;
import
ProgressBar
from
'
./ProgressItem
'
;
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/progress.scss
'
;
import
'
../../static/style/probar.scss
'
;
import
'
../../static/style/probar.scss
'
;
interface
ProgressProps
{
interface
ProgressProps
{
concurrency
:
number
;
concurrency
:
number
;
bestAccuracy
:
number
;
bestAccuracy
:
number
;
...
@@ -19,24 +19,106 @@ interface ProgressProps {
...
@@ -19,24 +19,106 @@ interface ProgressProps {
interface
ProgressState
{
interface
ProgressState
{
isShowLogDrawer
:
boolean
;
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
>
{
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
)
{
constructor
(
props
:
ProgressProps
)
{
super
(
props
);
super
(
props
);
this
.
state
=
{
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
>
=>
{
editTrialConcurrency
=
async
(
userInput
:
string
):
Promise
<
void
>
=>
{
if
(
!
userInput
.
match
(
/^
[
1-9
]\d
*$/
))
{
if
(
!
userInput
.
match
(
/^
[
1-9
]\d
*$/
))
{
message
.
error
(
'
Please enter a positive integer!
'
,
2
);
this
.
showMessageInfo
(
'
Please enter a positive integer!
'
,
'
error
'
);
return
;
return
;
}
}
const
newConcurrency
=
parseInt
(
userInput
,
10
);
const
newConcurrency
=
parseInt
(
userInput
,
10
);
if
(
newConcurrency
===
this
.
props
.
concurrency
)
{
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
;
return
;
}
}
...
@@ -50,19 +132,19 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
...
@@ -50,19 +132,19 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
params
:
{
update_type
:
'
TRIAL_CONCURRENCY
'
}
params
:
{
update_type
:
'
TRIAL_CONCURRENCY
'
}
});
});
if
(
res
.
status
===
200
)
{
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?
// NOTE: should we do this earlier in favor of poor networks?
this
.
props
.
changeConcurrency
(
newConcurrency
);
this
.
props
.
changeConcurrency
(
newConcurrency
);
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
if
(
error
.
response
&&
error
.
response
.
data
.
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
)
{
}
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
)
{
}
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
{
}
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> {
...
@@ -75,55 +157,79 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
this
.
setState
({
isShowLogDrawer
:
false
});
this
.
setState
({
isShowLogDrawer
:
false
});
}
}
onDismiss
=
():
void
=>
{
this
.
setState
({
isCalloutVisible
:
false
});
}
onShow
=
():
void
=>
{
this
.
setState
({
isCalloutVisible
:
true
});
}
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
bestAccuracy
}
=
this
.
props
;
const
{
bestAccuracy
}
=
this
.
props
;
const
{
isShowLogDrawer
}
=
this
.
state
;
const
{
isShowLogDrawer
,
isCalloutVisible
,
isShowSucceedInfo
,
info
,
typeInfo
}
=
this
.
state
;
const
count
=
TRIALS
.
countStatus
();
const
count
=
TRIALS
.
countStatus
();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const
stoppedCount
=
count
.
get
(
'
USER_CANCELED
'
)
!
+
count
.
get
(
'
SYS_CANCELED
'
)
!
+
count
.
get
(
'
EARLY_STOPPED
'
)
!
;
const
stoppedCount
=
count
.
get
(
'
USER_CANCELED
'
)
!
+
count
.
get
(
'
SYS_CANCELED
'
)
!
+
count
.
get
(
'
EARLY_STOPPED
'
)
!
;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const
bar2
=
count
.
get
(
'
RUNNING
'
)
!
+
count
.
get
(
'
SUCCEEDED
'
)
!
+
count
.
get
(
'
FAILED
'
)
!
+
stoppedCount
;
const
bar2
=
count
.
get
(
'
RUNNING
'
)
!
+
count
.
get
(
'
SUCCEEDED
'
)
!
+
count
.
get
(
'
FAILED
'
)
!
+
stoppedCount
;
// support type [0, 1], not 98%
const
bar2Percent
=
(
bar2
/
EXPERIMENT
.
profile
.
params
.
maxTrialNum
)
*
100
;
const
bar2Percent
=
bar2
/
EXPERIMENT
.
profile
.
params
.
maxTrialNum
;
const
percent
=
(
EXPERIMENT
.
profile
.
execDuration
/
EXPERIMENT
.
profile
.
params
.
maxExecDuration
)
*
100
;
const
percent
=
EXPERIMENT
.
profile
.
execDuration
/
EXPERIMENT
.
profile
.
params
.
maxExecDuration
;
const
remaining
=
convertTime
(
EXPERIMENT
.
profile
.
params
.
maxExecDuration
-
EXPERIMENT
.
profile
.
execDuration
);
const
remaining
=
convertTime
(
EXPERIMENT
.
profile
.
params
.
maxExecDuration
-
EXPERIMENT
.
profile
.
execDuration
);
const
maxDuration
=
convertTime
(
EXPERIMENT
.
profile
.
params
.
maxExecDuration
);
const
maxDuration
=
convertTime
(
EXPERIMENT
.
profile
.
params
.
maxExecDuration
);
const
maxTrialNum
=
EXPERIMENT
.
profile
.
params
.
maxTrialNum
;
const
maxTrialNum
=
EXPERIMENT
.
profile
.
params
.
maxTrialNum
;
const
execDuration
=
convertTime
(
EXPERIMENT
.
profile
.
execDuration
);
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
(
return
(
<
Row
className
=
"progress"
id
=
"barBack"
>
<
Stack
className
=
"progress"
id
=
"barBack"
>
<
Row
className
=
"basic lineBasic"
>
<
Stack
className
=
"basic lineBasic"
>
<
p
>
Status
</
p
>
<
p
>
Status
</
p
>
<
div
className
=
"status"
>
<
Stack
horizontal
className
=
"status"
>
<
span
className
=
{
EXPERIMENT
.
status
}
>
{
EXPERIMENT
.
status
}
</
span
>
<
span
className
=
{
`
${
EXPERIMENT
.
status
}
status-text`
}
>
{
EXPERIMENT
.
status
}
</
span
>
{
{
EXPERIMENT
.
status
===
'
ERROR
'
EXPERIMENT
.
status
===
'
ERROR
'
?
?
<
Popover
<
div
>
placement
=
"rightTop"
<
div
className
=
{
styles
.
buttonArea
}
ref
=
{
(
val
):
any
=>
this
.
menuButtonElement
=
val
}
>
content
=
{
errorContent
}
<
IconButton
title
=
"Error"
iconProps
=
{
{
iconName
:
'
info
'
}
}
trigger
=
"hover"
onClick
=
{
isCalloutVisible
?
this
.
onDismiss
:
this
.
onShow
}
>
/>
<
span
className
=
"errorBtn"
>
i
</
span
>
</
div
>
</
Popover
>
{
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
>
</
Stack
>
</
Row
>
</
Stack
>
<
ProgressBar
<
ProgressBar
who
=
"Duration"
who
=
"Duration"
percent
=
{
percent
}
percent
=
{
percent
}
...
@@ -138,55 +244,49 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
...
@@ -138,55 +244,49 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
bgclass
=
{
EXPERIMENT
.
status
}
bgclass
=
{
EXPERIMENT
.
status
}
maxString
=
{
`Max trial number:
${
maxTrialNum
}
`
}
maxString
=
{
`Max trial number:
${
maxTrialNum
}
`
}
/>
/>
<
Row
className
=
"basic colorOfbasic mess"
>
<
Stack
className
=
"basic colorOfbasic mess"
horizontal
>
<
p
>
Best metric
</
p
>
<
StackItem
grow
=
{
50
}
>
<
div
>
{
isNaN
(
bestAccuracy
)
?
'
N/A
'
:
bestAccuracy
.
toFixed
(
6
)
}
</
div
>
<
p
>
Best metric
</
p
>
</
Row
>
<
div
>
{
isNaN
(
bestAccuracy
)
?
'
N/A
'
:
bestAccuracy
.
toFixed
(
6
)
}
</
div
>
<
Row
className
=
"mess"
>
</
StackItem
>
<
Col
span
=
{
6
}
>
<
StackItem
>
<
Row
className
=
"basic colorOfbasic"
>
{
isShowSucceedInfo
&&
<
MessageInfo
className
=
"info"
typeInfo
=
{
typeInfo
}
info
=
{
info
}
/>
}
<
p
>
Spent
</
p
>
</
StackItem
>
<
div
>
{
execDuration
}
</
div
>
</
Stack
>
</
Row
>
<
Stack
horizontal
horizontalAlign
=
"space-between"
className
=
"mess"
>
</
Col
>
<
span
style
=
{
itemStyles
}
className
=
"basic colorOfbasic"
>
<
Col
span
=
{
6
}
>
<
p
>
Spent
</
p
>
<
Row
className
=
"basic colorOfbasic"
>
<
div
>
{
execDuration
}
</
div
>
<
p
>
Remaining
</
p
>
</
span
>
<
div
className
=
"time"
>
{
remaining
}
</
div
>
<
span
style
=
{
itemStyles
}
className
=
"basic colorOfbasic"
>
</
Row
>
<
p
>
Remaining
</
p
>
</
Col
>
<
div
className
=
"time"
>
{
remaining
}
</
div
>
<
Col
span
=
{
12
}
>
</
span
>
<
span
style
=
{
itemStyles
}
>
{
/* modify concurrency */
}
{
/* modify concurrency */
}
<
p
>
Concurrency
</
p
>
<
p
>
Concurrency
</
p
>
<
ConcurrencyInput
value
=
{
this
.
props
.
concurrency
}
updateValue
=
{
this
.
editTrialConcurrency
}
/>
<
ConcurrencyInput
value
=
{
this
.
props
.
concurrency
}
updateValue
=
{
this
.
editTrialConcurrency
}
/>
</
Col
>
</
span
>
</
Row
>
<
span
style
=
{
itemStyles
}
className
=
"basic colorOfbasic"
></
span
>
<
Row
className
=
"mess"
>
</
Stack
>
<
Col
span
=
{
6
}
>
<
Stack
horizontal
horizontalAlign
=
"space-between"
className
=
"mess"
>
<
Row
className
=
"basic colorOfbasic"
>
<
div
style
=
{
itemStyles
}
className
=
"basic colorOfbasic"
>
<
p
>
Running
</
p
>
<
p
>
Running
</
p
>
<
div
>
{
count
.
get
(
'
RUNNING
'
)
}
</
div
>
<
div
>
{
count
.
get
(
'
RUNNING
'
)
}
</
div
>
</
Row
>
</
div
>
</
Col
>
<
div
style
=
{
itemStyles
}
className
=
"basic colorOfbasic"
>
<
Col
span
=
{
6
}
>
<
p
>
Succeeded
</
p
>
<
Row
className
=
"basic colorOfbasic"
>
<
div
>
{
count
.
get
(
'
SUCCEEDED
'
)
}
</
div
>
<
p
>
Succeeded
</
p
>
</
div
>
<
div
>
{
count
.
get
(
'
SUCCEEDED
'
)
}
</
div
>
<
div
style
=
{
itemStyles
}
className
=
"basic"
>
</
Row
>
<
p
>
Stopped
</
p
>
</
Col
>
<
div
>
{
stoppedCount
}
</
div
>
<
Col
span
=
{
6
}
>
</
div
>
<
Row
className
=
"basic"
>
<
div
style
=
{
itemStyles
}
className
=
"basic"
>
<
p
>
Stopped
</
p
>
<
p
>
Failed
</
p
>
<
div
>
{
stoppedCount
}
</
div
>
<
div
>
{
count
.
get
(
'
FAILED
'
)
}
</
div
>
</
Row
>
</
div
>
</
Col
>
</
Stack
>
<
Col
span
=
{
6
}
>
<
Row
className
=
"basic"
>
<
p
>
Failed
</
p
>
<
div
>
{
count
.
get
(
'
FAILED
'
)
}
</
div
>
</
Row
>
</
Col
>
</
Row
>
{
/* learn about click -> default active key is dispatcher. */
}
{
/* learn about click -> default active key is dispatcher. */
}
{
isShowLogDrawer
?
(
{
isShowLogDrawer
?
(
<
LogDrawer
<
LogDrawer
...
@@ -194,9 +294,10 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
...
@@ -194,9 +294,10 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
activeTab
=
"dispatcher"
activeTab
=
"dispatcher"
/>
/>
)
:
null
}
)
:
null
}
</
Row
>
</
Stack
>
);
);
}
}
}
}
export
default
Progressed
;
export
default
Progressed
;
src/webui/src/components/overview/ProgressItem.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Row
,
Col
,
Progress
}
from
'
antd
'
;
import
{
Stack
,
StackItem
,
ProgressIndicator
}
from
'
office-ui-fabric-react
'
;
interface
ProItemProps
{
interface
ProItemProps
{
who
:
string
;
who
:
string
;
...
@@ -18,29 +18,23 @@ class ProgressBar extends React.Component<ProItemProps, {}> {
...
@@ -18,29 +18,23 @@ class ProgressBar extends React.Component<ProItemProps, {}> {
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
who
,
percent
,
description
,
maxString
,
bgclass
}
=
this
.
props
;
const
{
who
,
percent
,
description
,
maxString
,
bgclass
}
=
this
.
props
;
return
(
return
(
<
div
>
<
div
>
<
Row
className
=
{
`probar
${
bgclass
}
`
}
>
<
Stack
horizontal
className
=
{
`probar
${
bgclass
}
`
}
>
<
Col
span
=
{
8
}
>
<
div
className
=
"name"
>
{
who
}
</
div
>
<
div
className
=
"name"
>
{
who
}
</
div
>
<
div
className
=
"showProgress"
style
=
{
{
width
:
'
80%
'
}
}
>
</
Col
>
<
ProgressIndicator
<
Col
span
=
{
16
}
className
=
"bar"
>
barHeight
=
{
30
}
<
div
className
=
"showProgress"
>
percentComplete
=
{
percent
}
<
Progress
/>
percent
=
{
percent
}
<
Stack
horizontal
className
=
"boundary"
>
strokeWidth
=
{
30
}
<
StackItem
grow
=
{
30
}
>
0
</
StackItem
>
// strokeLinecap={'square'}
<
StackItem
className
=
"right"
grow
=
{
70
}
>
{
maxString
}
</
StackItem
>
format
=
{
():
string
=>
description
}
</
Stack
>
/>
</
div
>
</
div
>
<
div
className
=
"description"
style
=
{
{
width
:
'
20%
'
}
}
>
{
description
}
</
div
>
<
Row
className
=
"description"
>
</
Stack
>
<
Col
span
=
{
9
}
>
0
</
Col
>
<
br
/>
<
Col
className
=
"right"
span
=
{
15
}
>
{
maxString
}
</
Col
>
</
Row
>
</
Col
>
</
Row
>
<
br
/>
</
div
>
</
div
>
);
);
}
}
...
...
src/webui/src/components/overview/SearchSpace.tsx
View file @
aa316742
...
@@ -18,7 +18,6 @@ class SearchSpace extends React.Component<SearchspaceProps, {}> {
...
@@ -18,7 +18,6 @@ class SearchSpace extends React.Component<SearchspaceProps, {}> {
return
(
return
(
<
div
className
=
"searchSpace"
>
<
div
className
=
"searchSpace"
>
<
MonacoEditor
<
MonacoEditor
width
=
"100%"
height
=
"361"
height
=
"361"
language
=
"json"
language
=
"json"
theme
=
"vs-light"
theme
=
"vs-light"
...
...
src/webui/src/components/overview/SuccessTable.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Table
}
from
'
antd
'
;
import
{
DetailsList
,
IDetailsListProps
,
IColumn
}
from
'
office-ui-fabric-react
'
;
import
OpenRow
from
'
../public-child/OpenRow
'
;
import
DefaultMetric
from
'
../public-child/DefaultMetric
'
;
import
DefaultMetric
from
'
../public-child/DefaultMetrc
'
;
import
Details
from
'
./Details
'
;
import
{
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
TableRecord
}
from
'
../../static/interface
'
;
import
{
convertDuration
}
from
'
../../static/function
'
;
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
'
;
import
'
../../static/style/openRow.scss
'
;
interface
SuccessTableProps
{
interface
SuccessTableProps
{
trialIds
:
string
[];
trialIds
:
string
[];
}
}
function
openRow
(
record
:
TableRecord
):
any
{
interface
SuccessTableState
{
return
(
columns
:
IColumn
[];
<
OpenRow
trialId
=
{
record
.
id
}
/>
source
:
Array
<
any
>
;
);
}
}
class
SuccessTable
extends
React
.
Component
<
SuccessTableProps
,
{}
>
{
class
SuccessTable
extends
React
.
Component
<
SuccessTableProps
,
SuccessTableState
>
{
constructor
(
props
:
SuccessTableProps
)
{
constructor
(
props
:
SuccessTableProps
)
{
super
(
props
);
super
(
props
);
this
.
state
=
{
columns
:
this
.
columns
,
source
:
TRIALS
.
table
(
this
.
props
.
trialIds
)
};
}
}
render
():
React
.
ReactNode
{
private
onRenderRow
:
IDetailsListProps
[
'
onRenderRow
'
]
=
props
=>
{
const
columns
=
[
if
(
props
)
{
{
return
<
Details
detailsProps
=
{
props
}
/>;
title
:
'
Trial No.
'
,
}
dataIndex
:
'
sequenceId
'
,
return
null
;
className
:
'
tableHead
'
};
},
{
title
:
'
ID
'
,
onColumnClick
=
(
ev
:
React
.
MouseEvent
<
HTMLElement
>
,
getColumn
:
IColumn
):
void
=>
{
dataIndex
:
'
id
'
,
const
{
columns
,
source
}
=
this
.
state
;
width
:
80
,
const
newColumns
:
IColumn
[]
=
columns
.
slice
();
className
:
'
tableHead leftTitle
'
,
const
currColumn
:
IColumn
=
newColumns
.
filter
(
item
=>
getColumn
.
key
===
item
.
key
)[
0
];
render
:
(
text
:
string
,
record
:
TableRecord
):
React
.
ReactNode
=>
{
newColumns
.
forEach
((
newCol
:
IColumn
)
=>
{
return
(
if
(
newCol
===
currColumn
)
{
<
div
>
{
record
.
id
}
</
div
>
currColumn
.
isSortedDescending
=
!
currColumn
.
isSortedDescending
;
);
currColumn
.
isSorted
=
true
;
},
}
else
{
},
{
newCol
.
isSorted
=
false
;
title
:
'
Duration
'
,
newCol
.
isSortedDescending
=
true
;
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
}
/>
);
}
}
}
];
});
// 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
(
return
(
<
div
className
=
"tabScroll"
>
<
div
id
=
"succTable"
>
<
Table
{
/* TODO: [style] lineHeight question */
}
<
DetailsList
columns
=
{
columns
}
columns
=
{
columns
}
expandedRowRender
=
{
openRow
}
items
=
{
source
}
dataSource
=
{
TRIALS
.
table
(
this
.
props
.
trialIds
)
}
setKey
=
"set"
className
=
"commonTableStyle"
compact
=
{
true
}
pagination
=
{
false
}
onRenderRow
=
{
this
.
onRenderRow
}
selectionMode
=
{
0
}
// close selector function
/>
/>
</
div
>
</
div
>
);
);
...
...
src/webui/src/components/overview/Title1.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Stack
}
from
'
office-ui-fabric-react
'
;
import
'
../../static/style/overviewTitle.scss
'
;
interface
Title1Props
{
interface
Title1Props
{
text
:
string
;
text
:
string
;
icon
?:
string
;
icon
?:
string
;
...
@@ -15,12 +16,10 @@ class Title1 extends React.Component<Title1Props, {}> {
...
@@ -15,12 +16,10 @@ class Title1 extends React.Component<Title1Props, {}> {
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
text
,
icon
,
bgcolor
}
=
this
.
props
;
const
{
text
,
icon
,
bgcolor
}
=
this
.
props
;
return
(
return
(
<
div
>
<
Stack
horizontal
className
=
"panelTitle"
style
=
{
{
backgroundColor
:
bgcolor
}
}
>
<
div
className
=
"panelTitle"
style
=
{
{
backgroundColor
:
bgcolor
}
}
>
<
img
src
=
{
require
(
`../../static/img/icon/
${
icon
}
`
)
}
alt
=
"icon"
/>
<
img
src
=
{
require
(
`../../static/img/icon/
${
icon
}
`
)
}
alt
=
"icon"
/>
<
span
>
{
text
}
</
span
>
<
span
>
{
text
}
</
span
>
</
Stack
>
</
div
>
</
div
>
);
);
}
}
}
}
...
...
src/webui/src/components/overview/TrialProfile.tsx
View file @
aa316742
...
@@ -27,7 +27,6 @@ class TrialInfo extends React.Component<TrialInfoProps, {}> {
...
@@ -27,7 +27,6 @@ class TrialInfo extends React.Component<TrialInfoProps, {}> {
};
};
const
profile
=
JSON
.
stringify
(
EXPERIMENT
.
profile
,
filter
,
2
);
const
profile
=
JSON
.
stringify
(
EXPERIMENT
.
profile
,
filter
,
2
);
// FIXME: highlight not working?
return
(
return
(
<
div
className
=
"profile"
>
<
div
className
=
"profile"
>
<
MonacoEditor
<
MonacoEditor
...
...
src/webui/src/components/public-child/DefaultMetrc.tsx
→
src/webui/src/components/public-child/DefaultMetr
i
c.tsx
View file @
aa316742
File moved
src/webui/src/components/public-child/LogPath.tsx
deleted
100644 → 0
View file @
3fe117f0
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 @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Spin
}
from
'
antd
'
;
import
{
Spin
ner
}
from
'
office-ui-fabric-react
'
;
import
{
DRAWEROPTION
}
from
'
../../static/const
'
;
import
{
DRAWEROPTION
}
from
'
../../static/const
'
;
import
MonacoEditor
from
'
react-monaco-editor
'
;
import
MonacoEditor
from
'
react-monaco-editor
'
;
...
@@ -11,7 +11,7 @@ interface MonacoEditorProps {
...
@@ -11,7 +11,7 @@ interface MonacoEditorProps {
class
MonacoHTML
extends
React
.
Component
<
MonacoEditorProps
,
{}
>
{
class
MonacoHTML
extends
React
.
Component
<
MonacoEditorProps
,
{}
>
{
public
_isMonacoMount
:
boolean
;
public
_isMonacoMount
!
:
boolean
;
constructor
(
props
:
MonacoEditorProps
)
{
constructor
(
props
:
MonacoEditorProps
)
{
super
(
props
);
super
(
props
);
...
@@ -25,23 +25,37 @@ class MonacoHTML extends React.Component<MonacoEditorProps, {}> {
...
@@ -25,23 +25,37 @@ class MonacoHTML extends React.Component<MonacoEditorProps, {}> {
this
.
_isMonacoMount
=
false
;
this
.
_isMonacoMount
=
false
;
}
}
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
content
,
loading
,
height
}
=
this
.
props
;
const
{
content
,
loading
,
height
}
=
this
.
props
;
return
(
return
(
<
div
className
=
"just-for-log"
>
<
div
className
=
"just-for-log"
>
<
Spin
{
// tip="Loading..."
loading
style
=
{
{
width
:
'
100%
'
,
height
:
height
}
}
?
spinning
=
{
loading
}
<
Spinner
>
label
=
"Wait, wait..."
<
MonacoEditor
ariaLive
=
"assertive"
width
=
"100%"
labelPosition
=
"right"
height
=
{
height
}
styles
=
{
{
root
:
{
width
:
'
100%
'
,
height
:
height
}
}
}
language
=
"json"
>
value
=
{
content
}
<
MonacoEditor
options
=
{
DRAWEROPTION
}
width
=
"100%"
/>
height
=
{
height
}
</
Spin
>
language
=
"json"
value
=
{
content
}
options
=
{
DRAWEROPTION
}
/>
</
Spinner
>
:
<
MonacoEditor
width
=
"100%"
height
=
{
height
}
language
=
"json"
value
=
{
content
}
options
=
{
DRAWEROPTION
}
/>
}
</
div
>
</
div
>
);
);
}
}
...
...
src/webui/src/components/public-child/OpenRow.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
*
as
copy
from
'
copy-to-clipboard
'
;
import
*
as
copy
from
'
copy-to-clipboard
'
;
import
PaiTrialLog
from
'
../public-child/PaiTrialLog
'
;
import
{
Stack
,
PrimaryButton
,
Pivot
,
PivotItem
}
from
'
office-ui-fabric-react
'
;
import
TrialLog
from
'
../public-child/TrialLog
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
Trial
}
from
'
../../static/model/trial
'
;
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
{
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/overview.scss
'
;
import
'
../../static/style/copyParameter.scss
'
;
import
'
../../static/style/copyParameter.scss
'
;
import
JSONTree
from
'
react-json-tree
'
;
const
TabPane
=
Tabs
.
TabPane
;
interface
OpenRowProps
{
interface
OpenRowProps
{
trialId
:
string
;
trialId
:
string
;
}
}
interface
OpenRowState
{
interface
OpenRowState
{
isShowFormatModal
:
boolean
;
typeInfo
:
string
;
formatStr
:
string
;
info
:
string
;
isHidenInfo
:
boolean
;
}
}
class
OpenRow
extends
React
.
Component
<
OpenRowProps
,
OpenRowState
>
{
class
OpenRow
extends
React
.
Component
<
OpenRowProps
,
OpenRowState
>
{
...
@@ -25,127 +26,111 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
...
@@ -25,127 +26,111 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
constructor
(
props
:
OpenRowProps
)
{
constructor
(
props
:
OpenRowProps
)
{
super
(
props
);
super
(
props
);
this
.
state
=
{
this
.
state
=
{
isShowFormatModal
:
false
,
typeInfo
:
''
,
formatStr
:
''
info
:
''
,
isHidenInfo
:
true
};
};
}
}
showFormatModal
=
(
trial
:
Trial
):
void
=>
{
hideMessageInfo
=
():
void
=>
{
// get copy parameters
this
.
setState
(()
=>
({
isHidenInfo
:
true
}));
const
params
=
JSON
.
stringify
(
trial
.
info
.
hyperParameters
,
null
,
4
);
// open modal with format string
this
.
setState
({
isShowFormatModal
:
true
,
formatStr
:
params
});
}
}
hideFormatModal
=
():
void
=>
{
/**
// close modal, destroy state format string data
* info: message content
this
.
setState
({
isShowFormatModal
:
false
,
formatStr
:
''
});
* 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
=>
{
copyParams
=
(
trial
:
Trial
):
void
=>
{
// json format
// get copy parameters
const
{
formatStr
}
=
this
.
state
;
const
params
=
JSON
.
stringify
(
trial
.
description
.
parameters
,
null
,
4
);
if
(
copy
(
formatStr
))
{
if
(
copy
.
default
(
params
))
{
message
.
destroy
();
this
.
getCopyStatus
(
'
Success copy parameters to clipboard in form of python dict !
'
,
'
success
'
);
message
.
success
(
'
Success copy parameters to clipboard in form of python dict !
'
,
3
);
}
else
{
}
else
{
message
.
destroy
();
this
.
getCopyStatus
(
'
Failed !
'
,
'
error
'
);
message
.
error
(
'
Failed !
'
,
2
);
}
}
this
.
hideFormatModal
();
}
}
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
is
ShowFormatModal
,
formatStr
}
=
this
.
state
;
const
{
is
HidenInfo
,
typeInfo
,
info
}
=
this
.
state
;
const
trialId
=
this
.
props
.
trialId
;
const
trialId
=
this
.
props
.
trialId
;
const
trial
=
TRIALS
.
getTrial
(
trialId
);
const
trial
=
TRIALS
.
getTrial
(
trialId
);
const
trialLink
:
string
=
`
${
MANAGER_IP
}
/trial-jobs/
${
trialId
}
`
;
const
trialLink
:
string
=
`
${
MANAGER_IP
}
/trial-jobs/
${
trialId
}
`
;
const
logPathRow
=
trial
.
info
.
logPath
||
'
This trial
\'
s log path is not available.
'
;
const
logPathRow
=
trial
.
info
.
logPath
||
'
This trial
\'
s log path is not available.
'
;
const
multiProgress
=
trial
.
info
.
hyperParameters
===
undefined
?
0
:
trial
.
info
.
hyperParameters
.
length
;
const
multiProgress
=
trial
.
info
.
hyperParameters
===
undefined
?
0
:
trial
.
info
.
hyperParameters
.
length
;
return
(
return
(
<
Row
className
=
"openRowContent hyperpar"
>
<
Stack
className
=
"openRow"
>
<
Tabs
tabPosition
=
"left"
className
=
"card"
>
<
Stack
className
=
"openRowContent"
>
<
TabPane
tab
=
"Parameters"
key
=
"1"
>
<
Pivot
>
{
<
PivotItem
headerText
=
"Parameters"
key
=
"1"
itemIcon
=
"TestParameter"
>
EXPERIMENT
.
multiPhase
{
?
EXPERIMENT
.
multiPhase
<
Row
className
=
"link"
>
?
Trails for multiphase experiment will return a set of parameters,
<
Stack
className
=
"link"
>
we are listing the latest parameter in webportal.
{
<
br
/>
`
For the entire parameter set, please refer to the following
"
Trails for multiphase experiment will return a set of parameters,
<
a
we are listing the latest parameter in webportal.
href
=
{
trialLink
}
For the entire parameter set, please refer to the following "
rel
=
"noopener noreferrer"
`
target
=
"_blank"
}
style
=
{
{
marginLeft
:
2
}
}
<
a
href
=
{
trialLink
}
rel
=
"noopener noreferrer"
target
=
"_blank"
>
{
trialLink
}
</
a
>
{
`".`
}
>
<
div
>
Current Phase:
{
multiProgress
}
.
</
div
>
{
trialLink
}
</
Stack
>
</
a
>
"
:
<
br
/>
null
Current Phase:
{
multiProgress
}
.
}
</
Row
>
{
:
trial
.
info
.
hyperParameters
!==
undefined
<
div
/>
?
}
<
Stack
id
=
"description"
>
{
<
Stack
className
=
"bgHyper"
>
trial
.
info
.
hyperParameters
!==
undefined
<
JSONTree
?
hideRoot
=
{
true
}
<
Row
id
=
"description"
>
shouldExpandNode
=
{
():
boolean
=>
true
}
// default expandNode
<
Row
className
=
"bgHyper"
>
getItemString
=
{
():
null
=>
null
}
// remove the {} items
<
JSONTree
data
=
{
trial
.
description
.
parameters
}
hideRoot
=
{
true
}
/>
shouldExpandNode
=
{
():
boolean
=>
true
}
// default expandNode
</
Stack
>
getItemString
=
{
():
any
=>
(<
span
/>)
}
// remove the {} items
<
Stack
horizontal
className
=
"copy"
>
data
=
{
trial
.
description
.
parameters
}
<
PrimaryButton
/>
onClick
=
{
this
.
copyParams
.
bind
(
this
,
trial
)
}
</
Row
>
text
=
"Copy as json"
<
Row
className
=
"copy"
>
styles
=
{
{
root
:
{
width
:
128
,
marginRight
:
10
}
}
}
<
Button
/>
onClick
=
{
this
.
showFormatModal
.
bind
(
this
,
trial
)
}
{
/* copy success | failed message info */
}
>
{
!
isHidenInfo
&&
<
MessageInfo
typeInfo
=
{
typeInfo
}
info
=
{
info
}
/>
}
Copy as json
</
Stack
>
</
Button
>
</
Stack
>
</
Row
>
:
</
Row
>
<
Stack
className
=
"logpath"
>
:
<
span
className
=
"logName"
>
Error:
</
span
>
<
Row
className
=
"logpath"
>
<
span
className
=
"error"
>
{
`This trial's parameters are not available.'`
}
</
span
>
<
span
className
=
"logName"
style
=
{
{
marginRight
:
2
}
}
>
Error:
</
span
>
</
Stack
>
<
span
className
=
"error"
>
'
This trial
'
s parameters are not available.
'
</
span
>
}
</
Row
>
</
PivotItem
>
}
<
PivotItem
headerText
=
"Log"
key
=
"2"
itemIcon
=
"M365InvoicingLogo"
>
</
TabPane
>
{
<
TabPane
tab
=
"Log"
key
=
"2"
>
// FIXME: this should not be handled in web UI side
{
EXPERIMENT
.
trainingServicePlatform
!==
'
local
'
// FIXME: this should not be handled in web UI side
?
EXPERIMENT
.
trainingServicePlatform
!==
'
local
'
<
PaiTrialLog
?
logStr
=
{
logPathRow
}
<
PaiTrialLog
id
=
{
trialId
}
logStr
=
{
logPathRow
}
logCollection
=
{
EXPERIMENT
.
logCollectionEnabled
}
id
=
{
trialId
}
/>
logCollection
=
{
EXPERIMENT
.
logCollectionEnabled
}
:
/>
<
TrialLog
logStr
=
{
logPathRow
}
id
=
{
trialId
}
/>
:
}
<
TrialLog
logStr
=
{
logPathRow
}
id
=
{
trialId
}
/>
</
PivotItem
>
}
</
Pivot
>
</
TabPane
>
</
Stack
>
</
Tabs
>
</
Stack
>
<
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
>
);
);
}
}
}
}
...
...
src/webui/src/components/public-child/PaiTrialChild.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Row
}
from
'
antd
'
;
import
{
DOWNLOAD_IP
}
from
'
../../static/const
'
;
import
{
DOWNLOAD_IP
}
from
'
../../static/const
'
;
interface
PaiTrialChildProps
{
interface
PaiTrialChildProps
{
...
@@ -24,7 +23,7 @@ class PaiTrialChild extends React.Component<PaiTrialChildProps, {}> {
...
@@ -24,7 +23,7 @@ class PaiTrialChild extends React.Component<PaiTrialChildProps, {}> {
?
?
<
div
/>
<
div
/>
:
:
<
Row
>
<
div
>
{
{
logCollect
logCollect
?
?
...
@@ -39,7 +38,7 @@ class PaiTrialChild extends React.Component<PaiTrialChildProps, {}> {
...
@@ -39,7 +38,7 @@ class PaiTrialChild extends React.Component<PaiTrialChildProps, {}> {
:
:
<
span
>
trial stdout:
{
logString
}
</
span
>
<
span
>
trial stdout:
{
logString
}
</
span
>
}
}
</
Row
>
</
div
>
}
}
</
div
>
</
div
>
);
);
...
...
src/webui/src/components/public-child/PaiTrialLog.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Row
}
from
'
antd
'
;
import
{
DOWNLOAD_IP
}
from
'
../../static/const
'
;
import
{
DOWNLOAD_IP
}
from
'
../../static/const
'
;
import
PaiTrialChild
from
'
./PaiTrialChild
'
;
import
PaiTrialChild
from
'
./PaiTrialChild
'
;
import
LogPathChild
from
'
./LogPathChild
'
;
import
LogPathChild
from
'
./LogPathChild
'
;
...
@@ -30,11 +29,11 @@ class PaitrialLog extends React.Component<PaitrialLogProps, {}> {
...
@@ -30,11 +29,11 @@ class PaitrialLog extends React.Component<PaitrialLogProps, {}> {
{
{
isTwopath
isTwopath
?
?
<
Row
>
<
div
>
{
{
logCollection
logCollection
?
?
<
Row
>
<
div
>
<
a
<
a
target
=
"_blank"
target
=
"_blank"
rel
=
"noopener noreferrer"
rel
=
"noopener noreferrer"
...
@@ -44,9 +43,9 @@ class PaitrialLog extends React.Component<PaitrialLogProps, {}> {
...
@@ -44,9 +43,9 @@ class PaitrialLog extends React.Component<PaitrialLogProps, {}> {
Trial stdout
Trial stdout
</
a
>
</
a
>
<
a
target
=
"_blank"
rel
=
"noopener noreferrer"
href
=
{
logStr
.
split
(
'
,
'
)[
1
]
}
>
hdfsLog
</
a
>
<
a
target
=
"_blank"
rel
=
"noopener noreferrer"
href
=
{
logStr
.
split
(
'
,
'
)[
1
]
}
>
hdfsLog
</
a
>
</
Row
>
</
div
>
:
:
<
Row
>
<
div
>
<
LogPathChild
<
LogPathChild
eachLogpath
=
{
logStr
.
split
(
'
,
'
)[
0
]
}
eachLogpath
=
{
logStr
.
split
(
'
,
'
)[
0
]
}
logName
=
"Trial stdout:"
logName
=
"Trial stdout:"
...
@@ -55,9 +54,9 @@ class PaitrialLog extends React.Component<PaitrialLogProps, {}> {
...
@@ -55,9 +54,9 @@ class PaitrialLog extends React.Component<PaitrialLogProps, {}> {
eachLogpath
=
{
logStr
.
split
(
'
,
'
)[
1
]
}
eachLogpath
=
{
logStr
.
split
(
'
,
'
)[
1
]
}
logName
=
"Log on HDFS:"
logName
=
"Log on HDFS:"
/>
/>
</
Row
>
</
div
>
}
}
</
Row
>
</
div
>
:
:
<
PaiTrialChild
<
PaiTrialChild
logString
=
{
logStr
}
logString
=
{
logStr
}
...
...
src/webui/src/components/trial-detail/DefaultMetricPoint.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Switch
}
from
'
antd
'
;
import
{
Toggle
,
Stack
}
from
'
office-ui-fabric-react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
Trial
}
from
'
../../static/model/trial
'
;
import
{
Trial
}
from
'
../../static/model/trial
'
;
import
{
TooltipForAccuracy
,
EventMap
}
from
'
../../static/interface
'
;
import
{
TooltipForAccuracy
,
EventMap
}
from
'
../../static/interface
'
;
require
(
'
echarts/lib/chart/scatter
'
);
import
'
echarts/lib/chart/scatter
'
;
require
(
'
echarts/lib/component/tooltip
'
);
import
'
echarts/lib/component/tooltip
'
;
require
(
'
echarts/lib/component/title
'
);
import
'
echarts/lib/component/title
'
;
const
EmptyGraph
=
{
const
EmptyGraph
=
{
grid
:
{
grid
:
{
left
:
'
8%
'
left
:
'
8%
'
...
@@ -18,9 +19,9 @@ const EmptyGraph = {
...
@@ -18,9 +19,9 @@ const EmptyGraph = {
yAxis
:
{
yAxis
:
{
name
:
'
Default metric
'
,
name
:
'
Default metric
'
,
type
:
'
value
'
,
type
:
'
value
'
,
scale
:
true
,
}
}
};
};
interface
DefaultPointProps
{
interface
DefaultPointProps
{
trialIds
:
string
[];
trialIds
:
string
[];
visible
:
boolean
;
visible
:
boolean
;
...
@@ -28,7 +29,7 @@ interface DefaultPointProps {
...
@@ -28,7 +29,7 @@ interface DefaultPointProps {
}
}
interface
DefaultPointState
{
interface
DefaultPointState
{
bestCurveEnabled
:
boolean
;
bestCurveEnabled
?
:
boolean
|
undefined
;
startY
:
number
;
// dataZoomY
startY
:
number
;
// dataZoomY
endY
:
number
;
endY
:
number
;
}
}
...
@@ -39,11 +40,11 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
...
@@ -39,11 +40,11 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
this
.
state
=
{
this
.
state
=
{
bestCurveEnabled
:
false
,
bestCurveEnabled
:
false
,
startY
:
0
,
// dataZoomY
startY
:
0
,
// dataZoomY
endY
:
100
,
endY
:
100
};
};
}
}
loadDefault
=
(
checked
:
boolean
):
void
=>
{
loadDefault
=
(
ev
:
React
.
MouseEvent
<
HTMLElement
>
,
checked
?
:
boolean
):
void
=>
{
this
.
setState
({
bestCurveEnabled
:
checked
});
this
.
setState
({
bestCurveEnabled
:
checked
});
}
}
...
@@ -51,7 +52,59 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
...
@@ -51,7 +52,59 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
return
nextProps
.
visible
;
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
=>
[
const
data
=
trials
.
map
(
trial
=>
[
trial
.
sequenceId
,
trial
.
sequenceId
,
trial
.
accuracy
,
trial
.
accuracy
,
...
@@ -63,27 +116,24 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
...
@@ -63,27 +116,24 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
data
,
data
,
};
};
}
}
generateBestCurveSeries
=
(
trials
:
Trial
[]):
any
=>
{
generateBestCurveSeries
(
trials
:
Trial
[]):
any
{
let
best
=
trials
[
0
];
let
best
=
trials
[
0
];
const
data
=
[[
best
.
sequenceId
,
best
.
accuracy
,
best
.
description
.
parameters
]];
const
data
=
[[
best
.
sequenceId
,
best
.
accuracy
,
best
.
description
.
parameters
]];
for
(
let
i
=
1
;
i
<
trials
.
length
;
i
++
)
{
for
(
let
i
=
1
;
i
<
trials
.
length
;
i
++
)
{
const
trial
=
trials
[
i
];
const
trial
=
trials
[
i
];
if
(
trial
.
accuracy
!==
undefined
)
{
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
if
(
best
.
accuracy
!==
undefined
)
{
const
delta
=
trial
.
accuracy
!
-
best
.
accuracy
!
;
const
delta
=
trial
.
accuracy
-
best
.
accuracy
;
const
better
=
(
EXPERIMENT
.
optimizeMode
===
'
minimize
'
)
?
(
delta
<
0
)
:
(
delta
>
0
);
const
better
=
(
EXPERIMENT
.
optimizeMode
===
'
minimize
'
)
?
(
delta
<
0
)
:
(
delta
>
0
);
if
(
better
)
{
if
(
better
)
{
data
.
push
([
trial
.
sequenceId
,
trial
.
accuracy
,
trial
.
description
.
parameters
]);
data
.
push
([
trial
.
sequenceId
,
trial
.
accuracy
,
trial
.
description
.
parameters
]);
best
=
trial
;
best
=
trial
;
}
else
{
}
else
{
data
.
push
([
trial
.
sequenceId
,
best
.
accuracy
,
trial
.
description
.
parameters
]);
data
.
push
([
trial
.
sequenceId
,
best
.
accuracy
,
trial
.
description
.
parameters
]);
}
}
}
}
}
}
return
{
return
{
type
:
'
line
'
,
type
:
'
line
'
,
lineStyle
:
{
color
:
'
#FF6600
'
},
lineStyle
:
{
color
:
'
#FF6600
'
},
...
@@ -98,24 +148,26 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
...
@@ -98,24 +148,26 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
return
(
return
(
<
div
>
<
div
>
<
div
className
=
"default-metric"
>
<
Stack
horizontalAlign
=
"end"
className
=
"default-metric"
>
<
div
className
=
"position"
>
<
Toggle
label
=
"Optimization curve"
<
span
className
=
"bold"
>
Optimization curve
</
span
>
inlineLabel
<
Switch
defaultChecked
=
{
false
}
onChange
=
{
this
.
loadDefault
}
/>
onChange
=
{
this
.
loadDefault
}
</
div
>
/>
</
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
>
</
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
>
</
div
>
);
);
}
}
...
@@ -133,58 +185,6 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
...
@@ -133,58 +185,6 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
}
}
return
graph
;
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
;
export
default
DefaultPoint
;
src/webui/src/components/trial-detail/Duration.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
{
TableObj
,
EventMap
}
from
'
src
/static/interface
'
;
import
{
TableObj
,
EventMap
}
from
'
../..
/static/interface
'
;
// eslint-disable-line no-unused-vars
import
{
filterDuration
}
from
'
src
/static/function
'
;
import
{
filterDuration
}
from
'
../..
/static/function
'
;
require
(
'
echarts/lib/chart/bar
'
)
;
import
'
echarts/lib/chart/bar
'
;
require
(
'
echarts/lib/component/tooltip
'
)
;
import
'
echarts/lib/component/tooltip
'
;
require
(
'
echarts/lib/component/title
'
)
;
import
'
echarts/lib/component/title
'
;
interface
Runtrial
{
interface
Runtrial
{
trialId
:
Array
<
string
>
;
trialId
:
string
[]
;
trialTime
:
number
[];
trialTime
:
number
[];
}
}
...
@@ -19,6 +19,7 @@ interface DurationProps {
...
@@ -19,6 +19,7 @@ interface DurationProps {
interface
DurationState
{
interface
DurationState
{
startDuration
:
number
;
// for record data zoom
startDuration
:
number
;
// for record data zoom
endDuration
:
number
;
endDuration
:
number
;
durationSource
:
{};
}
}
class
Duration
extends
React
.
Component
<
DurationProps
,
DurationState
>
{
class
Duration
extends
React
.
Component
<
DurationProps
,
DurationState
>
{
...
@@ -29,6 +30,59 @@ class Duration extends React.Component<DurationProps, DurationState> {
...
@@ -29,6 +30,59 @@ class Duration extends React.Component<DurationProps, DurationState> {
this
.
state
=
{
this
.
state
=
{
startDuration
:
0
,
// for record data zoom
startDuration
:
0
,
// for record data zoom
endDuration
:
100
,
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> {
...
@@ -45,7 +99,7 @@ class Duration extends React.Component<DurationProps, DurationState> {
bottom
:
'
3%
'
,
bottom
:
'
3%
'
,
containLabel
:
true
,
containLabel
:
true
,
left
:
'
1%
'
,
left
:
'
1%
'
,
right
:
'
4
%
'
right
:
'
5
%
'
},
},
dataZoom
:
[
dataZoom
:
[
{
{
...
@@ -64,7 +118,10 @@ class Duration extends React.Component<DurationProps, DurationState> {
...
@@ -64,7 +118,10 @@ class Duration extends React.Component<DurationProps, DurationState> {
yAxis
:
{
yAxis
:
{
name
:
'
Trial
'
,
name
:
'
Trial
'
,
type
:
'
category
'
,
type
:
'
category
'
,
data
:
dataObj
.
trialId
data
:
dataObj
.
trialId
,
nameTextStyle
:
{
padding
:
[
0
,
0
,
0
,
30
]
}
},
},
series
:
[{
series
:
[{
type
:
'
bar
'
,
type
:
'
bar
'
,
...
@@ -73,11 +130,11 @@ class Duration extends React.Component<DurationProps, DurationState> {
...
@@ -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?
// why this function run two times when props changed?
const
trialId
:
Array
<
string
>
=
[];
const
trialId
:
string
[]
=
[];
const
trialTime
:
number
[]
=
[];
const
trialTime
:
number
[]
=
[];
const
trialRun
:
Array
<
Runtrial
>
=
[];
const
trialRun
:
Runtrial
[]
=
[];
const
trialJobs
=
source
.
filter
(
filterDuration
);
const
trialJobs
=
source
.
filter
(
filterDuration
);
Object
.
keys
(
trialJobs
).
map
(
item
=>
{
Object
.
keys
(
trialJobs
).
map
(
item
=>
{
const
temp
=
trialJobs
[
item
];
const
temp
=
trialJobs
[
item
];
...
@@ -88,7 +145,21 @@ class Duration extends React.Component<DurationProps, DurationState> {
...
@@ -88,7 +145,21 @@ class Duration extends React.Component<DurationProps, DurationState> {
trialId
:
trialId
,
trialId
:
trialId
,
trialTime
:
trialTime
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
{
shouldComponentUpdate
(
nextProps
:
DurationProps
):
boolean
{
...
@@ -117,15 +188,13 @@ class Duration extends React.Component<DurationProps, DurationState> {
...
@@ -117,15 +188,13 @@ class Duration extends React.Component<DurationProps, DurationState> {
}
}
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
durationSource
}
=
this
.
state
;
const
{
source
}
=
this
.
props
;
const
graph
=
this
.
drawDurationGraph
(
source
);
const
onEvents
=
{
'
dataZoom
'
:
this
.
durationDataZoom
};
const
onEvents
=
{
'
dataZoom
'
:
this
.
durationDataZoom
};
return
(
return
(
<
div
>
<
div
>
<
ReactEcharts
<
ReactEcharts
option
=
{
graph
}
option
=
{
durationSource
}
style
=
{
{
width
:
'
9
5
%
'
,
height
:
412
,
margin
:
'
0 auto
'
}
}
style
=
{
{
width
:
'
9
4
%
'
,
height
:
412
,
margin
:
'
0 auto
'
,
marginTop
:
15
}
}
theme
=
"my_theme"
theme
=
"my_theme"
notMerge
=
{
true
}
// update now
notMerge
=
{
true
}
// update now
onEvents
=
{
onEvents
}
onEvents
=
{
onEvents
}
...
...
src/webui/src/components/trial-detail/Intermediate.tsx
View file @
aa316742
import
*
as
React
from
'
react
'
;
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
{
TooltipForIntermediate
,
TableObj
,
Intermedia
,
EventMap
}
from
'
../../static/interface
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
require
(
'
echarts/lib/component/tooltip
'
);
import
'
echarts/lib/component/tooltip
'
;
require
(
'
echarts/lib/component/title
'
);
import
'
echarts/lib/component/title
'
;
const
stackTokens
:
IStackTokens
=
{
childrenGap
:
20
};
interface
IntermediateState
{
interface
IntermediateState
{
detailSource
:
Array
<
TableObj
>
;
detailSource
:
Array
<
TableObj
>
;
...
@@ -11,7 +15,7 @@ interface IntermediateState {
...
@@ -11,7 +15,7 @@ interface IntermediateState {
filterSource
:
Array
<
TableObj
>
;
filterSource
:
Array
<
TableObj
>
;
eachIntermediateNum
:
number
;
// trial's intermediate number count
eachIntermediateNum
:
number
;
// trial's intermediate number count
isLoadconfirmBtn
:
boolean
;
isLoadconfirmBtn
:
boolean
;
isFilter
:
boolean
;
isFilter
?
:
boolean
|
undefined
;
length
:
number
;
length
:
number
;
clickCounts
:
number
;
// user filter intermediate click confirm btn's counts
clickCounts
:
number
;
// user filter intermediate click confirm btn's counts
startMediaY
:
number
;
startMediaY
:
number
;
...
@@ -26,9 +30,9 @@ interface IntermediateProps {
...
@@ -26,9 +30,9 @@ interface IntermediateProps {
class
Intermediate
extends
React
.
Component
<
IntermediateProps
,
IntermediateState
>
{
class
Intermediate
extends
React
.
Component
<
IntermediateProps
,
IntermediateState
>
{
static
intervalMediate
=
1
;
static
intervalMediate
=
1
;
public
pointInput
:
HTMLInputElement
|
null
;
public
pointInput
!
:
HTMLInputElement
|
null
;
public
minValInput
:
HTMLInputElement
|
null
;
public
minValInput
!
:
HTMLInputElement
|
null
;
public
maxValInput
:
HTMLInputElement
|
null
;
public
maxValInput
!
:
HTMLInputElement
|
null
;
constructor
(
props
:
IntermediateProps
)
{
constructor
(
props
:
IntermediateProps
)
{
super
(
props
);
super
(
props
);
...
@@ -65,7 +69,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
...
@@ -65,7 +69,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
});
});
// find max intermediate number
// find max intermediate number
trialIntermediate
.
sort
((
a
,
b
)
=>
{
return
(
b
.
data
.
length
-
a
.
data
.
length
);
});
trialIntermediate
.
sort
((
a
,
b
)
=>
{
return
(
b
.
data
.
length
-
a
.
data
.
length
);
});
const
legend
:
Array
<
string
>
=
[];
const
legend
:
string
[]
=
[];
// max length
// max length
const
length
=
trialIntermediate
[
0
].
data
.
length
;
const
length
=
trialIntermediate
[
0
].
data
.
length
;
const
xAxis
:
number
[]
=
[];
const
xAxis
:
number
[]
=
[];
...
@@ -87,7 +91,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
...
@@ -87,7 +91,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
return
[
point
[
0
]
-
300
,
80
];
return
[
point
[
0
]
-
300
,
80
];
}
}
},
},
formatter
:
function
(
data
:
TooltipForIntermediate
):
any
{
formatter
:
function
(
data
:
TooltipForIntermediate
):
React
.
ReactNode
{
const
trialId
=
data
.
seriesName
;
const
trialId
=
data
.
seriesName
;
let
obj
=
{};
let
obj
=
{};
const
temp
=
trialIntermediate
.
find
(
key
=>
key
.
name
===
trialId
);
const
temp
=
trialIntermediate
.
find
(
key
=>
key
.
name
===
trialId
);
...
@@ -116,7 +120,8 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
...
@@ -116,7 +120,8 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
},
},
yAxis
:
{
yAxis
:
{
type
:
'
value
'
,
type
:
'
value
'
,
name
:
'
Metric
'
name
:
'
Metric
'
,
scale
:
true
,
},
},
dataZoom
:
[
dataZoom
:
[
{
{
...
@@ -195,7 +200,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
...
@@ -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
});
this
.
setState
({
isFilter
:
checked
});
if
(
checked
===
false
)
{
if
(
checked
===
false
)
{
this
.
drawIntermediate
(
this
.
props
.
source
);
this
.
drawIntermediate
(
this
.
props
.
source
);
...
@@ -226,62 +231,18 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
...
@@ -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
{
render
():
React
.
ReactNode
{
const
{
interSource
,
isLoadconfirmBtn
,
isFilter
}
=
this
.
state
;
const
{
interSource
,
isLoadconfirmBtn
,
isFilter
}
=
this
.
state
;
const
IntermediateEvents
=
{
'
dataZoom
'
:
this
.
intermediateDataZoom
};
const
IntermediateEvents
=
{
'
dataZoom
'
:
this
.
intermediateDataZoom
};
return
(
return
(
<
div
>
<
div
>
{
/* style in para.scss */
}
{
/* style in para.scss */
}
<
Row
className
=
"meline intermediate"
>
<
Stack
horizontal
horizontalAlign
=
"end"
tokens
=
{
stackTokens
}
className
=
"meline intermediate"
>
{
{
isFilter
isFilter
?
?
<
span
style
=
{
{
marginRight
:
15
}
}
>
<
div
>
<
span
className
=
"filter-x"
>
# Intermediate result
</
span
>
<
span
className
=
"filter-x"
>
# Intermediate result
</
span
>
<
input
<
input
// placeholder="point"
// placeholder="point"
...
@@ -298,34 +259,31 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
...
@@ -298,34 +259,31 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
// placeholder="range"
// placeholder="range"
ref
=
{
(
input
):
any
=>
this
.
maxValInput
=
input
}
ref
=
{
(
input
):
any
=>
this
.
maxValInput
=
input
}
/>
/>
<
Button
<
PrimaryButton
type
=
"primary"
text
=
"Confirm"
className
=
"changeBtu tableButton"
onClick
=
{
this
.
filterLines
}
onClick
=
{
this
.
filterLines
}
disabled
=
{
isLoadconfirmBtn
}
disabled
=
{
isLoadconfirmBtn
}
>
/>
Confirm
</
div
>
</
Button
>
</
span
>
:
:
null
null
}
}
{
/* filter message */
}
{
/* filter message */
}
<
span
>
Filter
</
span
>
<
Stack
horizontal
className
=
"filter-toggle"
>
<
Switch
<
span
>
Filter
</
span
>
defaultChecked
=
{
false
}
<
Toggle
onChange
=
{
this
.
switchTurn
}
/>
onChange
=
{
this
.
switchTurn
}
</
Stack
>
/>
</
Row
>
</
Stack
>
<
Row
className
=
"intermediate-graph"
>
<
div
className
=
"intermediate-graph"
>
<
ReactEcharts
<
ReactEcharts
option
=
{
interSource
}
option
=
{
interSource
}
style
=
{
{
width
:
'
100%
'
,
height
:
4
18
,
margin
:
'
0 auto
'
}
}
style
=
{
{
width
:
'
100%
'
,
height
:
4
00
,
margin
:
'
0 auto
'
}
}
notMerge
=
{
true
}
// update now
notMerge
=
{
true
}
// update now
onEvents
=
{
IntermediateEvents
}
onEvents
=
{
IntermediateEvents
}
/>
/>
<
div
className
=
"yAxis"
>
# Intermediate result
</
div
>
<
div
className
=
"yAxis"
>
# Intermediate result
</
div
>
</
Row
>
</
div
>
</
div
>
</
div
>
);
);
}
}
...
...
Prev
1
…
8
9
10
11
12
13
14
15
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