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
1cd7ad5f
Unverified
Commit
1cd7ad5f
authored
Oct 12, 2020
by
Lijiaoa
Committed by
GitHub
Oct 12, 2020
Browse files
[webui] refactor overview page (#2924)
parent
0a6c234a
Changes
67
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
603 additions
and
710 deletions
+603
-710
src/webui/src/App.scss
src/webui/src/App.scss
+2
-2
src/webui/src/App.tsx
src/webui/src/App.tsx
+14
-30
src/webui/src/components/Overview.tsx
src/webui/src/components/Overview.tsx
+118
-126
src/webui/src/components/TrialsDetail.tsx
src/webui/src/components/TrialsDetail.tsx
+8
-5
src/webui/src/components/buttons/Icon.tsx
src/webui/src/components/buttons/Icon.tsx
+8
-2
src/webui/src/components/overview/Accuracy.tsx
src/webui/src/components/overview/Accuracy.tsx
+1
-1
src/webui/src/components/overview/BasicInfo.tsx
src/webui/src/components/overview/BasicInfo.tsx
+0
-43
src/webui/src/components/overview/NumInput.tsx
src/webui/src/components/overview/NumInput.tsx
+0
-65
src/webui/src/components/overview/Progress.tsx
src/webui/src/components/overview/Progress.tsx
+0
-315
src/webui/src/components/overview/ProgressItem.tsx
src/webui/src/components/overview/ProgressItem.tsx
+0
-42
src/webui/src/components/overview/SearchSpace.tsx
src/webui/src/components/overview/SearchSpace.tsx
+0
-30
src/webui/src/components/overview/Title.tsx
src/webui/src/components/overview/Title.tsx
+16
-0
src/webui/src/components/overview/TitleContext.tsx
src/webui/src/components/overview/TitleContext.tsx
+6
-0
src/webui/src/components/overview/TrialProfile.tsx
src/webui/src/components/overview/TrialProfile.tsx
+0
-49
src/webui/src/components/overview/count/EditExperimentParam.tsx
...bui/src/components/overview/count/EditExperimentParam.tsx
+147
-0
src/webui/src/components/overview/count/ExpDuration.tsx
src/webui/src/components/overview/count/ExpDuration.tsx
+54
-0
src/webui/src/components/overview/count/ExpDurationContext.tsx
...ebui/src/components/overview/count/ExpDurationContext.tsx
+7
-0
src/webui/src/components/overview/count/TrialCount.tsx
src/webui/src/components/overview/count/TrialCount.tsx
+107
-0
src/webui/src/components/overview/count/context.tsx
src/webui/src/components/overview/count/context.tsx
+17
-0
src/webui/src/components/overview/experiment/BasicInfo.tsx
src/webui/src/components/overview/experiment/BasicInfo.tsx
+98
-0
No files found.
src/webui/src/App.scss
View file @
1cd7ad5f
...
...
@@ -26,9 +26,9 @@
}
.content
{
width
:
89%
;
min-width
:
1024px
;
width
:
87%
;
margin
:
0
auto
;
min-width
:
1200px
;
margin-top
:
74px
;
margin-bottom
:
30px
;
}
...
...
src/webui/src/App.tsx
View file @
1cd7ad5f
...
...
@@ -4,6 +4,7 @@ import { COLUMN } from './static/const';
import
{
EXPERIMENT
,
TRIALS
}
from
'
./static/datamodel
'
;
import
NavCon
from
'
./components/NavCon
'
;
import
MessageInfo
from
'
./components/modals/MessageInfo
'
;
import
{
TrialConfigButton
}
from
'
./components/public-child/config/TrialConfigButton
'
;
import
'
./App.scss
'
;
interface
AppState
{
...
...
@@ -30,12 +31,13 @@ export const AppContext = React.createContext({
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
changeMetricGraphMode
:
(
val
:
'
max
'
|
'
min
'
)
=>
{},
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
changeEntries
:
(
val
:
string
)
=>
{}
changeEntries
:
(
val
:
string
)
=>
{},
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
updateOverviewPage
:
()
=>
{}
});
class
App
extends
React
.
Component
<
{},
AppState
>
{
private
timerId
!
:
number
|
undefined
;
private
dataFormatimer
!
:
number
;
private
firstLoad
:
boolean
=
false
;
// when click refresh selector options
constructor
(
props
:
{})
{
super
(
props
);
...
...
@@ -60,35 +62,8 @@ class App extends React.Component<{}, AppState> {
metricGraphMode
:
EXPERIMENT
.
optimizeMode
===
'
minimize
'
?
'
min
'
:
'
max
'
}));
this
.
timerId
=
window
.
setTimeout
(
this
.
refresh
,
this
.
state
.
interval
*
100
);
// final result is legal
// get a succeed trial,see final result data's format
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this
.
dataFormatimer
=
window
.
setInterval
(
this
.
getFinalDataFormat
,
this
.
state
.
interval
*
1000
);
}
getFinalDataFormat
=
():
void
=>
{
for
(
let
i
=
0
;
this
.
state
.
isillegalFinal
===
false
;
i
++
)
{
if
(
TRIALS
.
succeededTrials
()[
0
]
!==
undefined
&&
TRIALS
.
succeededTrials
()[
0
].
final
!==
undefined
)
{
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const
oneSucceedTrial
=
JSON
.
parse
(
JSON
.
parse
(
TRIALS
.
succeededTrials
()[
0
].
final
!
.
data
));
if
(
typeof
oneSucceedTrial
===
'
number
'
||
oneSucceedTrial
.
hasOwnProperty
(
'
default
'
))
{
window
.
clearInterval
(
this
.
dataFormatimer
);
break
;
}
else
{
// illegal final data
this
.
setState
(()
=>
({
isillegalFinal
:
true
,
expWarningMessage
:
'
WebUI support final result as number and dictornary includes default keys, your experiment final result is illegal, please check your data.
'
}));
window
.
clearInterval
(
this
.
dataFormatimer
);
}
}
else
{
break
;
}
}
};
changeInterval
=
(
interval
:
number
):
void
=>
{
window
.
clearTimeout
(
this
.
timerId
);
if
(
interval
===
0
)
{
...
...
@@ -116,6 +91,12 @@ class App extends React.Component<{}, AppState> {
this
.
setState
({
bestTrialEntries
:
entries
});
};
updateOverviewPage
=
():
void
=>
{
this
.
setState
(
state
=>
({
experimentUpdateBroadcast
:
state
.
experimentUpdateBroadcast
+
1
}));
};
shouldComponentUpdate
(
nextProps
:
any
,
nextState
:
AppState
):
boolean
{
if
(
!
(
nextState
.
isUpdate
||
nextState
.
isUpdate
===
undefined
))
{
nextState
.
isUpdate
=
true
;
...
...
@@ -155,6 +136,8 @@ class App extends React.Component<{}, AppState> {
</
div
>
<
Stack
className
=
'contentBox'
>
<
Stack
className
=
'content'
>
{
/* search space & config */
}
<
TrialConfigButton
/>
{
/* if api has error field, show error message */
}
{
errorList
.
map
(
(
item
,
key
)
=>
...
...
@@ -179,7 +162,8 @@ class App extends React.Component<{}, AppState> {
metricGraphMode
,
changeMetricGraphMode
:
this
.
changeMetricGraphMode
,
bestTrialEntries
,
changeEntries
:
this
.
changeEntries
changeEntries
:
this
.
changeEntries
,
updateOverviewPage
:
this
.
updateOverviewPage
}
}
>
{
this
.
props
.
children
}
...
...
src/webui/src/components/Overview.tsx
View file @
1cd7ad5f
import
*
as
React
from
'
react
'
;
import
{
Stack
,
I
StackTokens
,
Dropdow
n
}
from
'
@fluentui/react
'
;
import
{
Stack
,
I
con
,
Dropdown
,
DefaultButto
n
}
from
'
@fluentui/react
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../static/datamodel
'
;
import
{
Trial
}
from
'
../static/model/trial
'
;
import
{
AppContext
}
from
'
../App
'
;
import
{
Title1
}
from
'
./overview/Title1
'
;
import
SuccessTable
from
'
./overview/SuccessTable
'
;
import
Progressed
from
'
./overview/Progress
'
;
import
{
Title
}
from
'
./overview/Title
'
;
import
SuccessTable
from
'
./overview/table/SuccessTable
'
;
import
Accuracy
from
'
./overview/Accuracy
'
;
import
SearchSpace
from
'
./overview/SearchSpace
'
;
import
{
BasicInfo
}
from
'
./overview/BasicInfo
'
;
import
TrialInfo
from
'
./overview/TrialProfile
'
;
import
'
../static/style/overview.scss
'
;
import
{
ReBasicInfo
}
from
'
./overview/experiment/BasicInfo
'
;
import
{
ExpDuration
}
from
'
./overview/count/ExpDuration
'
;
import
{
ExpDurationContext
}
from
'
./overview/count/ExpDurationContext
'
;
import
{
TrialCount
}
from
'
./overview/count/TrialCount
'
;
import
{
Command
}
from
'
./overview/experiment/Command
'
;
import
{
TitleContext
}
from
'
./overview/TitleContext
'
;
import
{
itemStyle1
,
itemStyleSucceed
,
itemStyle2
,
entriesOption
}
from
'
./overview/overviewConst
'
;
import
'
../static/style/overview/overview.scss
'
;
import
'
../static/style/logPath.scss
'
;
const
stackTokens
:
IStackTokens
=
{
childrenGap
:
30
};
const
entriesOption
=
[
{
key
:
'
10
'
,
text
:
'
Display top 10 trials
'
},
{
key
:
'
20
'
,
text
:
'
Display top 20 trials
'
},
{
key
:
'
30
'
,
text
:
'
Display top 30 trials
'
},
{
key
:
'
50
'
,
text
:
'
Display top 50 trials
'
},
{
key
:
'
100
'
,
text
:
'
Display top 100 trials
'
}
];
interface
OverviewState
{
trialConcurrency
:
number
;
}
export
const
TitleContext
=
React
.
createContext
({
text
:
''
,
icon
:
''
,
fontColor
:
''
export
const
BestMetricContext
=
React
.
createContext
({
bestAccuracy
:
0
});
class
Overview
extends
React
.
Component
<
{},
OverviewState
>
{
static
contextType
=
AppContext
;
context
!
:
React
.
ContextType
<
typeof
AppContext
>
;
constructor
(
props
)
{
super
(
props
);
...
...
@@ -58,11 +48,6 @@ class Overview extends React.Component<{}, OverviewState> {
changeMetricGraphMode
(
'
min
'
);
};
changeConcurrency
=
(
val
:
number
):
void
=>
{
this
.
setState
({
trialConcurrency
:
val
});
};
// updateEntries = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption | undefined): void => {
updateEntries
=
(
event
:
React
.
FormEvent
<
HTMLDivElement
>
,
item
:
any
):
void
=>
{
if
(
item
!==
undefined
)
{
this
.
context
.
changeEntries
(
item
.
key
);
...
...
@@ -70,118 +55,125 @@ class Overview extends React.Component<{}, OverviewState> {
};
render
():
React
.
ReactNode
{
const
{
trialConcurrency
}
=
this
.
state
;
const
bestTrials
=
this
.
findBestTrials
();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const
bestAccuracy
=
bestTrials
.
length
>
0
?
bestTrials
[
0
].
accuracy
!
:
NaN
;
const
accuracyGraphData
=
this
.
generateAccuracyGraph
(
bestTrials
);
const
noDataMessage
=
bestTrials
.
length
>
0
?
''
:
'
No data
'
;
const
maxExecDuration
=
EXPERIMENT
.
profile
.
params
.
maxExecDuration
;
const
execDuration
=
EXPERIMENT
.
profile
.
execDuration
;
return
(
<
AppContext
.
Consumer
>
{
(
value
):
React
.
ReactNode
=>
{
const
{
experimentUpdateBroadcast
,
metricGraphMode
,
bestTrialEntries
}
=
value
;
const
titleMaxbgcolor
=
metricGraphMode
===
'
max
'
?
'
#333
'
:
'
#b3b3b3
'
;
const
titleMinbgcolor
=
metricGraphMode
===
'
min
'
?
'
#333
'
:
'
#b3b3b3
'
;
const
{
metricGraphMode
,
bestTrialEntries
,
updateOverviewPage
}
=
value
;
const
maxActive
=
metricGraphMode
===
'
max
'
?
'
active
'
:
'
'
;
const
minActive
=
metricGraphMode
===
'
min
'
?
'
active
'
:
'
'
;
return
(
<
div
className
=
'overview'
>
{
/* status and experiment block */
}
<
Stack
className
=
'bottomDiv bgNNI'
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Experiment
'
,
icon
:
'
11.png
'
,
fontColor
:
''
}
}
>
<
Title1
/>
</
TitleContext
.
Provider
>
<
BasicInfo
/>
</
Stack
>
<
Stack
horizontal
className
=
'overMessage bottomDiv'
>
{
/* status block */
}
<
Stack
.
Item
grow
className
=
'prograph bgNNI borderRight'
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Status
'
,
icon
:
'
5.png
'
,
fontColor
:
''
}
}
>
<
Title1
/>
</
TitleContext
.
Provider
>
<
Progressed
bestAccuracy
=
{
bestAccuracy
}
concurrency
=
{
trialConcurrency
}
changeConcurrency
=
{
this
.
changeConcurrency
}
experimentUpdateBroadcast
=
{
experimentUpdateBroadcast
}
/>
</
Stack
.
Item
>
{
/* experiment parameters search space tuner assessor... */
}
<
Stack
.
Item
grow
styles
=
{
{
root
:
{
width
:
450
}
}
}
className
=
'overviewBoder borderRight bgNNI'
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Search space
'
,
icon
:
'
10.png
'
,
fontColor
:
''
}
}
>
<
Title1
/>
<
div
className
=
'wrapper'
>
{
/* exp params */
}
<
div
className
=
'overviewBasicInfo'
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Experiment
'
,
icon
:
'
AutoRacing
'
}
}
>
<
Title
/>
</
TitleContext
.
Provider
>
<
Stack
className
=
'experiment'
>
<
SearchSpace
searchSpace
=
{
EXPERIMENT
.
searchSpace
}
/>
</
Stack
>
</
Stack
.
Item
>
<
Stack
.
Item
grow
styles
=
{
{
root
:
{
width
:
450
}
}
}
className
=
'bgNNI'
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Config
'
,
icon
:
'
4.png
'
,
fontColor
:
''
}
}
>
<
Title1
/>
</
TitleContext
.
Provider
>
<
Stack
className
=
'experiment'
>
{
/* the scroll bar all the trial profile in the searchSpace div*/
}
<
div
className
=
'experiment searchSpace'
>
<
TrialInfo
experimentUpdateBroadcast
=
{
experimentUpdateBroadcast
}
concurrency
=
{
trialConcurrency
}
/>
</
div
>
</
Stack
>
</
Stack
.
Item
>
</
Stack
>
<
Stack
style
=
{
{
backgroundColor
:
'
#fff
'
}
}
>
<
Stack
horizontal
className
=
'top10bg'
style
=
{
{
position
:
'
relative
'
,
height
:
42
}
}
>
<
div
className
=
'title'
onClick
=
{
this
.
clickMaxTop
}
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Top maximal trials
'
,
icon
:
'
max.png
'
,
fontColor
:
titleMaxbgcolor
}
}
>
<
Title1
/>
<
BestMetricContext
.
Provider
value
=
{
{
bestAccuracy
:
bestAccuracy
}
}
>
<
ReBasicInfo
/>
</
BestMetricContext
.
Provider
>
</
div
>
{
/* duration & trial numbers */
}
<
div
className
=
'overviewProgress'
>
<
div
className
=
'duration'
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Duration
'
,
icon
:
'
Timer
'
}
}
>
<
Title
/>
</
TitleContext
.
Provider
>
</
div
>
<
div
className
=
'title minTitle'
onClick
=
{
this
.
clickMinTop
}
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Top minimal trials
'
,
icon
:
'
min.png
'
,
fontColor
:
titleMinbgcolor
}
}
<
ExpDurationContext
.
Provider
value
=
{
{
maxExecDuration
,
execDuration
,
updateOverviewPage
}
}
>
<
Title1
/>
</
TitleContext
.
Provider
>
</
div
>
<
div
style
=
{
{
position
:
'
absolute
'
,
right
:
'
2%
'
,
top
:
8
}
}
>
<
Dropdown
selectedKey
=
{
bestTrialEntries
}
options
=
{
entriesOption
}
onChange
=
{
this
.
updateEntries
}
styles
=
{
{
root
:
{
width
:
170
}
}
}
/>
<
ExpDuration
/>
</
ExpDurationContext
.
Provider
>
</
div
>
</
Stack
>
<
Stack
horizontal
tokens
=
{
stackTokens
}
>
<
div
style
=
{
{
width
:
'
40%
'
,
position
:
'
relative
'
}
}
>
<
Accuracy
accuracyData
=
{
accuracyGraphData
}
accNodata
=
{
noDataMessage
}
height
=
{
404
}
/>
</
div
>
<
div
style
=
{
{
width
:
'
60%
'
}
}
>
<
SuccessTable
trialIds
=
{
bestTrials
.
map
(
trial
=>
trial
.
info
.
id
)
}
/>
<
div
className
=
'empty'
/>
<
div
className
=
'trialCount'
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Trial numbers
'
,
icon
:
'
NumberSymbol
'
}
}
>
<
Title
/>
</
TitleContext
.
Provider
>
<
ExpDurationContext
.
Provider
value
=
{
{
maxExecDuration
,
execDuration
,
updateOverviewPage
}
}
>
<
TrialCount
/>
</
ExpDurationContext
.
Provider
>
</
div
>
</
Stack
>
</
Stack
>
</
div
>
{
/* table */
}
<
div
className
=
'overviewTable'
>
<
Stack
horizontal
>
<
div
style
=
{
itemStyleSucceed
}
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Top trials
'
,
icon
:
'
BulletedList
'
}
}
>
<
Title
/>
</
TitleContext
.
Provider
>
</
div
>
<
div
className
=
'topTrialTitle'
>
{
/* <Stack horizontal horizontalAlign='space-between'> */
}
<
Stack
horizontal
horizontalAlign
=
'end'
>
<
DefaultButton
onClick
=
{
this
.
clickMaxTop
}
className
=
{
maxActive
}
styles
=
{
{
root
:
{
minWidth
:
70
,
padding
:
0
}
}
}
>
<
Icon
iconName
=
'Market'
/>
<
span
className
=
'max'
>
Max
</
span
>
</
DefaultButton
>
<
div
className
=
'mincenter'
>
<
DefaultButton
onClick
=
{
this
.
clickMinTop
}
className
=
{
minActive
}
styles
=
{
{
root
:
{
minWidth
:
70
,
padding
:
0
}
}
}
>
<
Icon
iconName
=
'MarketDown'
/>
<
span
className
=
'max'
>
Min
</
span
>
</
DefaultButton
>
</
div
>
<
div
>
<
Stack
horizontal
>
<
div
className
=
'chooseEntry'
>
Display top
</
div
>
<
div
>
<
Dropdown
selectedKey
=
{
bestTrialEntries
}
options
=
{
entriesOption
}
onChange
=
{
this
.
updateEntries
}
styles
=
{
{
root
:
{
width
:
70
}
}
}
/>
</
div
>
</
Stack
>
</
div
>
</
Stack
>
</
div
>
</
Stack
>
<
SuccessTable
trialIds
=
{
bestTrials
.
map
(
trial
=>
trial
.
info
.
id
)
}
/>
</
div
>
<
div
className
=
'overviewCommand'
>
<
Command
/>
</
div
>
<
div
className
=
'overviewChart'
>
<
Stack
horizontal
>
<
div
style
=
{
itemStyle1
}
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Trial metric chart
'
,
icon
:
'
HomeGroup
'
}
}
>
<
Title
/>
</
TitleContext
.
Provider
>
</
div
>
<
div
style
=
{
itemStyle2
}
>
<
Stack
className
=
'maxmin'
horizontal
>
<
div
className
=
'circle'
/>
<
div
>
{
`Top
${
this
.
context
.
metricGraphMode
}
imal trials`
}
</
div
>
</
Stack
>
</
div
>
</
Stack
>
<
Accuracy
accuracyData
=
{
accuracyGraphData
}
accNodata
=
{
noDataMessage
}
height
=
{
380
}
/>
</
div
>
</
div
>
</
div
>
);
}
}
...
...
src/webui/src/components/TrialsDetail.tsx
View file @
1cd7ad5f
...
...
@@ -3,7 +3,8 @@ import { Stack, StackItem, Pivot, PivotItem, Dropdown, IDropdownOption, DefaultB
import
{
EXPERIMENT
,
TRIALS
}
from
'
../static/datamodel
'
;
import
{
Trial
}
from
'
../static/model/trial
'
;
import
{
AppContext
}
from
'
../App
'
;
import
{
tableListIcon
}
from
'
./buttons/Icon
'
;
import
{
Title
}
from
'
./overview/Title
'
;
import
{
TitleContext
}
from
'
./overview/TitleContext
'
;
import
DefaultPoint
from
'
./trial-detail/DefaultMetricPoint
'
;
import
Duration
from
'
./trial-detail/Duration
'
;
import
Para
from
'
./trial-detail/Para
'
;
...
...
@@ -28,6 +29,7 @@ interface TrialDetailState {
class
TrialsDetail
extends
React
.
Component
<
{},
TrialDetailState
>
{
static
contextType
=
AppContext
;
context
!
:
React
.
ContextType
<
typeof
AppContext
>
;
public
interAccuracy
=
0
;
public
interAllTableList
=
2
;
...
...
@@ -142,10 +144,11 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
</
Pivot
>
</
div
>
{
/* trial table list */
}
<
div
style
=
{
{
backgroundColor
:
'
#fff
'
}
}
>
<
Stack
horizontal
className
=
'panelTitle'
style
=
{
{
marginTop
:
10
}
}
>
<
span
style
=
{
{
marginRight
:
12
}
}
>
{
tableListIcon
}
</
span
>
<
span
>
Trial jobs
</
span
>
<
div
className
=
'bulletedList'
style
=
{
{
marginTop
:
18
}
}
>
<
Stack
className
=
'title'
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Trial jobs
'
,
icon
:
'
BulletedList
'
}
}
>
<
Title
/>
</
TitleContext
.
Provider
>
</
Stack
>
<
Stack
horizontal
className
=
'allList'
>
<
StackItem
grow
=
{
50
}
>
...
...
src/webui/src/components/buttons/Icon.tsx
View file @
1cd7ad5f
...
...
@@ -11,11 +11,14 @@ const copy = <Icon iconName='Copy' />;
const
tableListIcon
=
<
Icon
iconName
=
'BulletedList'
/>;
const
downLoadIcon
=
{
iconName
:
'
Download
'
};
const
infoIconAbout
=
{
iconName
:
'
info
'
};
const
timeIcon
=
{
iconName
:
'
Re
fresh
'
};
const
timeIcon
=
{
iconName
:
'
Re
minderTime
'
};
const
disableUpdates
=
{
iconName
:
'
DisableUpdates
'
};
const
requency
=
{
iconName
:
'
Timer
'
};
const
closeTimer
=
{
iconName
:
'
Blocked2
'
};
const
LineChart
=
<
Icon
iconName
=
'LineChart'
/>;
const
Edit
=
<
Icon
iconName
=
'Edit'
/>;
const
CheckMark
=
<
Icon
iconName
=
'CheckMark'
/>;
const
Cancel
=
<
Icon
iconName
=
'Cancel'
/>;
export
{
infoIcon
,
...
...
@@ -31,5 +34,8 @@ export {
disableUpdates
,
requency
,
closeTimer
,
LineChart
LineChart
,
Edit
,
CheckMark
,
Cancel
};
src/webui/src/components/overview/Accuracy.tsx
View file @
1cd7ad5f
...
...
@@ -22,7 +22,7 @@ class Accuracy extends React.Component<AccuracyProps, {}> {
render
():
React
.
ReactNode
{
const
{
accNodata
,
accuracyData
,
height
}
=
this
.
props
;
return
(
<
div
>
<
div
style
=
{
{
position
:
'
relative
'
}
}
>
<
ReactEcharts
option
=
{
accuracyData
}
style
=
{
{
...
...
src/webui/src/components/overview/BasicInfo.tsx
deleted
100644 → 0
View file @
0a6c234a
import
React
from
'
react
'
;
import
{
Stack
,
TooltipHost
}
from
'
@fluentui/react
'
;
import
{
EXPERIMENT
}
from
'
../../static/datamodel
'
;
import
{
formatTimestamp
}
from
'
../../static/function
'
;
export
const
BasicInfo
=
():
any
=>
(
<
Stack
horizontal
horizontalAlign
=
'space-between'
className
=
'main'
>
<
Stack
.
Item
grow
=
{
3
}
className
=
'padItem basic'
>
<
p
>
Name
</
p
>
<
div
>
{
EXPERIMENT
.
profile
.
params
.
experimentName
}
</
div
>
</
Stack
.
Item
>
<
Stack
.
Item
grow
=
{
3
}
className
=
'padItem basic'
>
<
p
>
ID
</
p
>
<
div
>
{
EXPERIMENT
.
profile
.
id
}
</
div
>
</
Stack
.
Item
>
<
Stack
.
Item
grow
=
{
3
}
className
=
'padItem basic'
>
<
p
>
Start time
</
p
>
<
div
className
=
'nowrap'
>
{
formatTimestamp
(
EXPERIMENT
.
profile
.
startTime
)
}
</
div
>
</
Stack
.
Item
>
<
Stack
.
Item
grow
=
{
3
}
className
=
'padItem basic'
>
<
p
>
End time
</
p
>
<
div
className
=
'nowrap'
>
{
formatTimestamp
(
EXPERIMENT
.
profile
.
endTime
)
}
</
div
>
</
Stack
.
Item
>
<
Stack
.
Item
className
=
'padItem basic'
>
<
p
>
Log directory
</
p
>
<
div
className
=
'nowrap'
>
<
TooltipHost
// Tooltip message content
content
=
{
EXPERIMENT
.
profile
.
logDir
||
'
unknown
'
}
calloutProps
=
{
{
gapSpace
:
0
}
}
styles
=
{
{
root
:
{
display
:
'
inline-block
'
}
}
}
>
{
/* show logDir */
}
{
EXPERIMENT
.
profile
.
logDir
||
'
unknown
'
}
</
TooltipHost
>
</
div
>
</
Stack
.
Item
>
<
Stack
.
Item
className
=
'padItem basic'
>
<
p
>
Training platform
</
p
>
<
div
className
=
'nowrap'
>
{
EXPERIMENT
.
profile
.
params
.
trainingServicePlatform
}
</
div
>
</
Stack
.
Item
>
</
Stack
>
);
src/webui/src/components/overview/NumInput.tsx
deleted
100644 → 0
View file @
0a6c234a
import
*
as
React
from
'
react
'
;
import
{
Stack
,
PrimaryButton
}
from
'
@fluentui/react
'
;
interface
ConcurrencyInputProps
{
value
:
number
;
updateValue
:
(
val
:
string
)
=>
void
;
}
interface
ConcurrencyInputStates
{
editting
:
boolean
;
}
class
ConcurrencyInput
extends
React
.
Component
<
ConcurrencyInputProps
,
ConcurrencyInputStates
>
{
private
input
=
React
.
createRef
<
HTMLInputElement
>
();
constructor
(
props
:
ConcurrencyInputProps
)
{
super
(
props
);
this
.
state
=
{
editting
:
false
};
}
save
=
():
void
=>
{
if
(
this
.
input
.
current
!==
null
)
{
this
.
props
.
updateValue
(
this
.
input
.
current
.
value
);
this
.
setState
({
editting
:
false
});
}
};
cancel
=
():
void
=>
{
this
.
setState
({
editting
:
false
});
};
edit
=
():
void
=>
{
this
.
setState
({
editting
:
true
});
};
render
():
React
.
ReactNode
{
if
(
this
.
state
.
editting
)
{
return
(
<
Stack
horizontal
className
=
'inputBox'
>
<
input
type
=
'number'
className
=
'concurrencyInput'
defaultValue
=
{
this
.
props
.
value
.
toString
()
}
ref
=
{
this
.
input
}
/>
<
PrimaryButton
text
=
'Save'
onClick
=
{
this
.
save
}
/>
<
PrimaryButton
text
=
'Cancel'
style
=
{
{
display
:
'
inline-block
'
,
marginLeft
:
1
}
}
onClick
=
{
this
.
cancel
}
/>
</
Stack
>
);
}
else
{
return
(
<
Stack
horizontal
className
=
'inputBox'
>
<
input
type
=
'number'
className
=
'concurrencyInput'
disabled
=
{
true
}
value
=
{
this
.
props
.
value
}
/>
<
PrimaryButton
text
=
'Edit'
onClick
=
{
this
.
edit
}
/>
</
Stack
>
);
}
}
}
export
default
ConcurrencyInput
;
src/webui/src/components/overview/Progress.tsx
deleted
100644 → 0
View file @
0a6c234a
import
*
as
React
from
'
react
'
;
import
{
Stack
,
Callout
,
Link
,
IconButton
,
FontWeights
,
mergeStyleSets
,
getId
,
getTheme
,
StackItem
,
TooltipHost
}
from
'
@fluentui/react
'
;
import
axios
from
'
axios
'
;
import
{
MANAGER_IP
,
CONCURRENCYTOOLTIP
}
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
'
../modals/LogPanel
'
;
import
MessageInfo
from
'
../modals/MessageInfo
'
;
import
{
infoIcon
}
from
'
../buttons/Icon
'
;
import
'
../../static/style/progress.scss
'
;
import
'
../../static/style/probar.scss
'
;
interface
ProgressProps
{
concurrency
:
number
;
bestAccuracy
:
number
;
changeConcurrency
:
(
val
:
number
)
=>
void
;
experimentUpdateBroadcast
:
number
;
}
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
,
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
*$/
))
{
this
.
showMessageInfo
(
'
Please enter a positive integer!
'
,
'
error
'
);
return
;
}
const
newConcurrency
=
parseInt
(
userInput
,
10
);
if
(
newConcurrency
===
this
.
props
.
concurrency
)
{
this
.
showMessageInfo
(
'
Trial concurrency has not changed
'
,
'
error
'
);
return
;
}
const
newProfile
=
Object
.
assign
({},
EXPERIMENT
.
profile
);
newProfile
.
params
.
trialConcurrency
=
newConcurrency
;
// rest api, modify trial concurrency value
try
{
const
res
=
await
axios
.
put
(
`
${
MANAGER_IP
}
/experiment`
,
newProfile
,
{
// eslint-disable-next-line @typescript-eslint/camelcase
params
:
{
update_type
:
'
TRIAL_CONCURRENCY
'
}
});
if
(
res
.
status
===
200
)
{
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
)
{
this
.
showMessageInfo
(
`Failed to update trial concurrency\n
${
error
.
response
.
data
.
error
}
`
,
'
error
'
);
}
else
if
(
error
.
response
)
{
this
.
showMessageInfo
(
`Failed to update trial concurrency\nServer responsed
${
error
.
response
.
status
}
`
,
'
error
'
);
}
else
if
(
error
.
message
)
{
this
.
showMessageInfo
(
`Failed to update trial concurrency\n
${
error
.
message
}
`
,
'
error
'
);
}
else
{
this
.
showMessageInfo
(
`Failed to update trial concurrency\nUnknown error`
,
'
error
'
);
}
}
};
isShowDrawer
=
():
void
=>
{
this
.
setState
({
isShowLogDrawer
:
true
});
};
closeDrawer
=
():
void
=>
{
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
,
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
;
// 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
);
return
(
<
Stack
className
=
'progress'
id
=
'barBack'
>
<
Stack
className
=
'basic lineBasic'
>
<
p
>
Status
</
p
>
<
Stack
horizontal
className
=
'status'
>
<
span
className
=
{
`
${
EXPERIMENT
.
status
}
status-text`
}
>
{
EXPERIMENT
.
status
}
</
span
>
{
EXPERIMENT
.
status
===
'
ERROR
'
?
(
<
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
>
)
:
null
}
</
Stack
>
</
Stack
>
<
ProgressBar
who
=
'Duration'
percent
=
{
percent
}
description
=
{
execDuration
}
bgclass
=
{
EXPERIMENT
.
status
}
maxString
=
{
`Max duration:
${
maxDuration
}
`
}
/>
<
ProgressBar
who
=
'Trial numbers'
percent
=
{
bar2Percent
}
description
=
{
bar2
.
toString
()
}
bgclass
=
{
EXPERIMENT
.
status
}
maxString
=
{
`Max trial number:
${
maxTrialNum
}
`
}
/>
<
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 */
}
<
TooltipHost
content
=
{
CONCURRENCYTOOLTIP
}
>
<
p
className
=
'cursor'
>
Concurrency
<
span
className
=
'progress-info'
>
{
infoIcon
}
</
span
>
</
p
>
</
TooltipHost
>
<
ConcurrencyInput
value
=
{
this
.
props
.
concurrency
}
updateValue
=
{
this
.
editTrialConcurrency
}
/>
</
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
closeDrawer
=
{
this
.
closeDrawer
}
activeTab
=
'dispatcher'
/>
:
null
}
</
Stack
>
);
}
}
export
default
Progressed
;
src/webui/src/components/overview/ProgressItem.tsx
deleted
100644 → 0
View file @
0a6c234a
import
*
as
React
from
'
react
'
;
import
{
Stack
,
StackItem
,
ProgressIndicator
}
from
'
@fluentui/react
'
;
interface
ProItemProps
{
who
:
string
;
percent
:
number
;
description
:
string
;
maxString
:
string
;
bgclass
:
string
;
}
class
ProgressBar
extends
React
.
Component
<
ProItemProps
,
{}
>
{
constructor
(
props
:
ProItemProps
)
{
super
(
props
);
}
render
():
React
.
ReactNode
{
const
{
who
,
percent
,
description
,
maxString
,
bgclass
}
=
this
.
props
;
return
(
<
div
>
<
Stack
horizontal
className
=
{
`probar
${
bgclass
}
`
}
>
<
div
className
=
'name'
>
{
who
}
</
div
>
<
div
className
=
'showProgress'
style
=
{
{
width
:
'
78%
'
}
}
>
<
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
:
'
22%
'
}
}
>
{
description
}
</
div
>
</
Stack
>
<
br
/>
</
div
>
);
}
}
export
default
ProgressBar
;
src/webui/src/components/overview/SearchSpace.tsx
deleted
100644 → 0
View file @
0a6c234a
import
*
as
React
from
'
react
'
;
import
MonacoEditor
from
'
react-monaco-editor
'
;
import
{
MONACO
}
from
'
../../static/const
'
;
interface
SearchspaceProps
{
searchSpace
:
object
;
}
class
SearchSpace
extends
React
.
Component
<
SearchspaceProps
,
{}
>
{
constructor
(
props
:
SearchspaceProps
)
{
super
(
props
);
}
render
():
React
.
ReactNode
{
const
{
searchSpace
}
=
this
.
props
;
return
(
<
div
className
=
'searchSpace'
>
<
MonacoEditor
height
=
'361'
language
=
'json'
theme
=
'vs-light'
value
=
{
JSON
.
stringify
(
searchSpace
,
null
,
2
)
}
options
=
{
MONACO
}
/>
</
div
>
);
}
}
export
default
SearchSpace
;
src/webui/src/components/overview/Title
1
.tsx
→
src/webui/src/components/overview/Title.tsx
View file @
1cd7ad5f
import
*
as
React
from
'
react
'
;
import
{
Stack
}
from
'
@fluentui/react
'
;
import
{
TitleContext
}
from
'
../Overview
'
;
import
'
../../static/style/overviewTitle.scss
'
;
import
React
from
'
react
'
;
import
{
Stack
,
Icon
,
initializeIcons
}
from
'
@fluentui/react
'
;
import
{
TitleContext
}
from
'
./TitleContext
'
;
import
'
../../static/style/overview/overviewTitle.scss
'
;
initializeIcons
();
export
const
Title
1
=
():
any
=>
(
export
const
Title
=
():
any
=>
(
<
TitleContext
.
Consumer
>
{
(
value
):
React
.
ReactNode
=>
(
<
Stack
horizontal
className
=
'panelTitle'
>
<
img
src
=
{
require
(
`../../static/img/icon/
${
value
.
icon
}
`
)
}
alt
=
'icon'
/>
<
span
style
=
{
{
color
:
value
.
fontColor
}
}
>
{
value
.
text
}
</
span
>
<
Icon
iconName
=
{
value
.
icon
}
/>
<
span
>
{
value
.
text
}
</
span
>
</
Stack
>
)
}
</
TitleContext
.
Consumer
>
...
...
src/webui/src/components/overview/TitleContext.tsx
0 → 100644
View file @
1cd7ad5f
import
*
as
React
from
'
react
'
;
export
const
TitleContext
=
React
.
createContext
({
text
:
''
,
icon
:
''
});
src/webui/src/components/overview/TrialProfile.tsx
deleted
100644 → 0
View file @
0a6c234a
import
*
as
React
from
'
react
'
;
import
MonacoEditor
from
'
react-monaco-editor
'
;
import
{
MONACO
}
from
'
../../static/const
'
;
import
{
EXPERIMENT
}
from
'
../../static/datamodel
'
;
interface
TrialInfoProps
{
experimentUpdateBroadcast
:
number
;
concurrency
:
number
;
}
class
TrialInfo
extends
React
.
Component
<
TrialInfoProps
,
{}
>
{
constructor
(
props
:
TrialInfoProps
)
{
super
(
props
);
}
render
():
React
.
ReactNode
{
const
blacklist
=
[
'
id
'
,
'
logDir
'
,
'
startTime
'
,
'
endTime
'
,
'
experimentName
'
,
'
searchSpace
'
,
'
trainingServicePlatform
'
];
const
filter
=
(
key
:
string
,
val
:
any
):
any
=>
{
if
(
key
===
'
trialConcurrency
'
)
{
return
this
.
props
.
concurrency
;
}
return
blacklist
.
includes
(
key
)
?
undefined
:
val
;
};
const
profile
=
JSON
.
stringify
(
EXPERIMENT
.
profile
,
filter
,
2
);
return
(
<
div
className
=
'profile'
>
<
MonacoEditor
width
=
'100%'
height
=
'361'
language
=
'json'
theme
=
'vs-light'
value
=
{
profile
}
options
=
{
MONACO
}
/>
</
div
>
);
}
}
export
default
TrialInfo
;
src/webui/src/components/overview/count/EditExperimentParam.tsx
0 → 100644
View file @
1cd7ad5f
import
React
,
{
useState
,
useCallback
,
useContext
}
from
'
react
'
;
import
axios
from
'
axios
'
;
import
{
EXPERIMENT
}
from
'
../../../static/datamodel
'
;
import
{
EditExpeParamContext
}
from
'
./context
'
;
import
{
MANAGER_IP
}
from
'
../../../static/const
'
;
import
{
convertTimeToSecond
}
from
'
../../../static/function
'
;
import
{
Edit
,
CheckMark
,
Cancel
}
from
'
../../buttons/Icon
'
;
import
MessageInfo
from
'
../../modals/MessageInfo
'
;
import
'
../../../static/style/overview/count.scss
'
;
const
DurationInputRef
=
React
.
createRef
<
HTMLInputElement
>
();
export
const
EditExperimentParam
=
():
any
=>
{
const
[
isShowPencil
,
setShowPencil
]
=
useState
(
true
);
const
[
isShowSucceedInfo
,
setShowSucceedInfo
]
=
useState
(
false
);
const
[
typeInfo
,
setTypeInfo
]
=
useState
(
''
);
const
[
info
,
setInfo
]
=
useState
(
''
);
const
showPencil
=
useCallback
(()
=>
{
setShowPencil
(
true
);
},
[]);
const
hidePencil
=
useCallback
(()
=>
{
setShowPencil
(
false
);
},
[]);
const
showSucceedInfo
=
useCallback
(()
=>
setShowSucceedInfo
(
true
),
[]);
const
hideSucceedInfo
=
useCallback
(()
=>
{
setShowSucceedInfo
(
false
);
},
[]);
const
{
title
,
field
,
editType
,
maxExecDuration
,
maxTrialNum
,
trialConcurrency
,
updateOverviewPage
}
=
useContext
(
EditExpeParamContext
);
let
defaultVal
=
''
;
let
editVal
=
''
;
if
(
title
===
'
Max duration
'
)
{
defaultVal
=
maxExecDuration
;
editVal
=
maxExecDuration
;
}
else
if
(
title
===
'
Max trial numbers
'
)
{
defaultVal
=
maxTrialNum
.
toString
();
editVal
=
maxTrialNum
.
toString
();
}
else
{
defaultVal
=
trialConcurrency
.
toString
();
editVal
=
trialConcurrency
.
toString
();
}
const
[
editInputVal
,
setEditValInput
]
=
useState
(
editVal
);
function
setInputVal
(
event
:
any
):
void
{
setEditValInput
(
event
.
target
.
value
);
}
function
cancelEdit
():
void
{
setEditValInput
(
defaultVal
);
showPencil
();
}
async
function
confirmEdit
():
Promise
<
void
>
{
const
isMaxDuration
=
title
===
'
Max duration
'
;
const
newProfile
=
Object
.
assign
({},
EXPERIMENT
.
profile
);
let
beforeParam
=
''
;
if
(
!
isMaxDuration
&&
!
editInputVal
.
match
(
/^
[
1-9
]\d
*$/
))
{
showMessageInfo
(
'
Please enter a positive integer!
'
,
'
error
'
);
return
;
}
if
(
isMaxDuration
)
{
beforeParam
=
maxExecDuration
;
}
else
if
(
title
===
'
Max trial numbers
'
)
{
beforeParam
=
maxTrialNum
.
toString
();
}
else
{
beforeParam
=
trialConcurrency
.
toString
();
}
if
(
editInputVal
===
beforeParam
)
{
showMessageInfo
(
`Trial
${
field
}
has not changed`
,
'
error
'
);
return
;
}
if
(
isMaxDuration
)
{
newProfile
.
params
[
field
]
=
convertTimeToSecond
(
editInputVal
);
}
else
{
newProfile
.
params
[
field
]
=
parseInt
(
editInputVal
,
10
);
}
// rest api, modify trial concurrency value
try
{
const
res
=
await
axios
.
put
(
`
${
MANAGER_IP
}
/experiment`
,
newProfile
,
{
// eslint-disable-next-line @typescript-eslint/camelcase
params
:
{
update_type
:
editType
}
});
if
(
res
.
status
===
200
)
{
showMessageInfo
(
`Successfully updated
${
field
}
`
,
'
success
'
);
}
}
catch
(
error
)
{
if
(
error
.
response
&&
error
.
response
.
data
.
error
)
{
showMessageInfo
(
`Failed to update trial
${
field
}
\n
${
error
.
response
.
data
.
error
}
`
,
'
error
'
);
}
else
if
(
error
.
response
)
{
showMessageInfo
(
`Failed to update trial
${
field
}
\nServer responsed
${
error
.
response
.
status
}
`
,
'
error
'
);
}
else
if
(
error
.
message
)
{
showMessageInfo
(
`Failed to update trial
${
field
}
\n
${
error
.
message
}
`
,
'
error
'
);
}
else
{
showMessageInfo
(
`Failed to update trial
${
field
}
\nUnknown error`
,
'
error
'
);
}
}
showPencil
();
updateOverviewPage
();
}
function
showMessageInfo
(
info
:
string
,
typeInfo
:
string
):
any
{
setInfo
(
info
);
setTypeInfo
(
typeInfo
);
showSucceedInfo
();
setTimeout
(
hideSucceedInfo
,
2000
);
}
return
(
<
EditExpeParamContext
.
Consumer
>
{
(
value
):
React
.
ReactNode
=>
{
return
(
<
React
.
Fragment
>
<
p
>
{
value
.
title
}
</
p
>
<
div
>
<
input
className
=
{
`
${
value
.
field
}
durationInput`
}
ref
=
{
DurationInputRef
}
disabled
=
{
isShowPencil
?
true
:
false
}
value
=
{
editInputVal
}
onChange
=
{
setInputVal
}
/>
{
isShowPencil
&&
(
<
span
className
=
'edit'
onClick
=
{
hidePencil
}
>
{
Edit
}
</
span
>
)
}
{
!
isShowPencil
&&
(
<
span
className
=
'series'
>
<
span
className
=
'confirm'
onClick
=
{
confirmEdit
}
>
{
CheckMark
}
</
span
>
<
span
className
=
'cancel'
onClick
=
{
cancelEdit
}
>
{
Cancel
}
</
span
>
</
span
>
)
}
{
isShowSucceedInfo
&&
<
MessageInfo
className
=
'info'
typeInfo
=
{
typeInfo
}
info
=
{
info
}
/>
}
</
div
>
</
React
.
Fragment
>
);
}
}
</
EditExpeParamContext
.
Consumer
>
);
};
src/webui/src/components/overview/count/ExpDuration.tsx
0 → 100644
View file @
1cd7ad5f
import
React
from
'
react
'
;
import
{
Stack
,
TooltipHost
,
ProgressIndicator
}
from
'
@fluentui/react
'
;
import
{
EXPERIMENT
}
from
'
../../../static/datamodel
'
;
import
{
CONTROLTYPE
}
from
'
../../../static/const
'
;
import
{
convertDuration
}
from
'
../../../static/function
'
;
import
{
EditExperimentParam
}
from
'
./EditExperimentParam
'
;
import
{
ExpDurationContext
}
from
'
./ExpDurationContext
'
;
import
{
EditExpeParamContext
}
from
'
./context
'
;
import
'
../../../static/style/overview/count.scss
'
;
const
itemStyle1
:
React
.
CSSProperties
=
{
width
:
'
62%
'
,
height
:
80
};
const
itemStyle2
:
React
.
CSSProperties
=
{
width
:
'
63%
'
,
height
:
80
,
textAlign
:
'
right
'
};
export
const
ExpDuration
=
():
any
=>
(
<
ExpDurationContext
.
Consumer
>
{
(
value
):
React
.
ReactNode
=>
{
const
{
maxExecDuration
,
execDuration
,
updateOverviewPage
}
=
value
;
const
tooltip
=
maxExecDuration
-
execDuration
;
const
maxExecDurationStr
=
convertDuration
(
maxExecDuration
);
const
percent
=
execDuration
/
maxExecDuration
;
return
(
<
Stack
horizontal
className
=
'ExpDuration'
>
<
div
style
=
{
itemStyle1
}
>
<
TooltipHost
content
=
{
`
${
convertDuration
(
tooltip
)}
remaining`
}
>
<
ProgressIndicator
percentComplete
=
{
percent
}
barHeight
=
{
15
}
/>
</
TooltipHost
>
</
div
>
<
div
style
=
{
itemStyle2
}
>
<
Stack
horizontal
></
Stack
>
<
EditExpeParamContext
.
Provider
value
=
{
{
editType
:
CONTROLTYPE
[
0
],
field
:
'
maxExecDuration
'
,
title
:
'
Max duration
'
,
maxExecDuration
:
maxExecDurationStr
,
maxTrialNum
:
EXPERIMENT
.
profile
.
params
.
maxTrialNum
,
trialConcurrency
:
EXPERIMENT
.
profile
.
params
.
trialConcurrency
,
updateOverviewPage
}
}
>
<
EditExperimentParam
/>
</
EditExpeParamContext
.
Provider
>
</
div
>
</
Stack
>
);
}
}
</
ExpDurationContext
.
Consumer
>
);
src/webui/src/components/overview/count/ExpDurationContext.tsx
0 → 100644
View file @
1cd7ad5f
import
React
from
'
react
'
;
export
const
ExpDurationContext
=
React
.
createContext
({
maxExecDuration
:
0
,
execDuration
:
0
,
// eslint-disable-next-line @typescript-eslint/no-empty-function
updateOverviewPage
:
():
void
=>
{}
});
src/webui/src/components/overview/count/TrialCount.tsx
0 → 100644
View file @
1cd7ad5f
import
*
as
React
from
'
react
'
;
import
{
Stack
,
TooltipHost
,
ProgressIndicator
}
from
'
@fluentui/react
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../../static/datamodel
'
;
import
{
CONTROLTYPE
}
from
'
../../../static/const
'
;
import
{
EditExperimentParam
}
from
'
./EditExperimentParam
'
;
import
{
EditExpeParamContext
}
from
'
./context
'
;
import
{
ExpDurationContext
}
from
'
./ExpDurationContext
'
;
const
itemStyles
:
React
.
CSSProperties
=
{
width
:
'
62%
'
};
const
itemStyle2
:
React
.
CSSProperties
=
{
width
:
'
63%
'
,
textAlign
:
'
right
'
};
const
itemStyle1
:
React
.
CSSProperties
=
{
width
:
'
30%
'
,
height
:
50
};
const
itemRunning
:
React
.
CSSProperties
=
{
width
:
'
42%
'
,
height
:
56
};
export
const
TrialCount
=
():
any
=>
{
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
;
// support type [0, 1], not 98%
const
bar2Percent
=
bar2
/
EXPERIMENT
.
profile
.
params
.
maxTrialNum
;
return
(
<
ExpDurationContext
.
Consumer
>
{
(
value
):
React
.
ReactNode
=>
{
const
{
updateOverviewPage
}
=
value
;
return
(
<
React
.
Fragment
>
<
Stack
horizontal
horizontalAlign
=
'space-between'
className
=
'ExpDuration'
>
<
div
style
=
{
itemStyles
}
>
<
TooltipHost
content
=
{
bar2
.
toString
()
}
>
<
ProgressIndicator
percentComplete
=
{
bar2Percent
}
barHeight
=
{
15
}
/>
</
TooltipHost
>
<
Stack
horizontal
className
=
'mess'
>
<
div
style
=
{
itemRunning
}
className
=
'basic'
>
<
p
>
Running
</
p
>
<
div
>
{
count
.
get
(
'
RUNNING
'
)
}
</
div
>
</
div
>
<
div
style
=
{
itemStyle1
}
className
=
'basic'
>
<
p
>
Failed
</
p
>
<
div
>
{
count
.
get
(
'
FAILED
'
)
}
</
div
>
</
div
>
<
div
style
=
{
itemStyle1
}
className
=
'basic'
>
<
p
>
Stopped
</
p
>
<
div
>
{
stoppedCount
}
</
div
>
</
div
>
</
Stack
>
<
Stack
horizontal
horizontalAlign
=
'space-between'
className
=
'mess'
>
<
div
style
=
{
itemStyle1
}
className
=
'basic'
>
<
p
>
Succeeded
</
p
>
<
div
>
{
count
.
get
(
'
SUCCEEDED
'
)
}
</
div
>
</
div
>
<
div
style
=
{
itemStyle1
}
className
=
'basic'
>
<
p
>
Waiting
</
p
>
<
div
>
{
count
.
get
(
'
WAITING
'
)
}
</
div
>
</
div
>
</
Stack
>
</
div
>
<
div
style
=
{
itemStyle2
}
>
<
EditExpeParamContext
.
Provider
value
=
{
{
title
:
'
Max trial numbers
'
,
field
:
'
maxTrialNum
'
,
editType
:
CONTROLTYPE
[
1
],
maxExecDuration
:
''
,
maxTrialNum
:
EXPERIMENT
.
profile
.
params
.
maxTrialNum
,
trialConcurrency
:
EXPERIMENT
.
profile
.
params
.
trialConcurrency
,
updateOverviewPage
}
}
>
<
EditExperimentParam
/>
</
EditExpeParamContext
.
Provider
>
<
EditExpeParamContext
.
Provider
value
=
{
{
title
:
'
Concurrency
'
,
field
:
'
trialConcurrency
'
,
editType
:
CONTROLTYPE
[
2
],
// maxExecDuration: EXPERIMENT.profile.params.maxExecDuration,
maxExecDuration
:
''
,
maxTrialNum
:
EXPERIMENT
.
profile
.
params
.
maxTrialNum
,
trialConcurrency
:
EXPERIMENT
.
profile
.
params
.
trialConcurrency
,
updateOverviewPage
}
}
>
<
EditExperimentParam
/>
</
EditExpeParamContext
.
Provider
>
</
div
>
</
Stack
>
</
React
.
Fragment
>
);
}
}
</
ExpDurationContext
.
Consumer
>
);
};
src/webui/src/components/overview/count/context.tsx
0 → 100644
View file @
1cd7ad5f
import
React
from
'
react
'
;
/***
* const CONTROLTYPE = ['MAX_EXEC_DURATION', 'MAX_TRIAL_NUM', 'TRIAL_CONCURRENCY', 'SEARCH_SPACE'];
* [0], 'MAX_EXEC_DURATION', params.maxExecDuration
* [1], 'MAX_TRIAL_NUM', params.maxTrialNum
* [2], 'TRIAL_CONCURRENCY', params.trialConcurrency
*/
export
const
EditExpeParamContext
=
React
.
createContext
({
editType
:
''
,
field
:
''
,
title
:
''
,
maxExecDuration
:
''
,
maxTrialNum
:
0
,
trialConcurrency
:
0
,
// eslint-disable-next-line @typescript-eslint/no-empty-function
updateOverviewPage
:
():
void
=>
{}
});
src/webui/src/components/overview/experiment/BasicInfo.tsx
0 → 100644
View file @
1cd7ad5f
import
React
,
{
useState
,
useCallback
}
from
'
react
'
;
import
{
Stack
,
Callout
,
Link
,
IconButton
}
from
'
@fluentui/react
'
;
import
LogDrawer
from
'
../../modals/LogPanel
'
;
import
{
EXPERIMENT
}
from
'
../../../static/datamodel
'
;
import
{
formatTimestamp
}
from
'
../../../static/function
'
;
import
{
useId
}
from
'
@uifabric/react-hooks
'
;
import
{
BestMetricContext
}
from
'
../../Overview
'
;
import
{
styles
}
from
'
./basicInfoStyles
'
;
import
'
../../../static/style/progress/progress.scss
'
;
import
'
../../../static/style/progress/probar.scss
'
;
export
const
ReBasicInfo
=
():
any
=>
{
const
labelId
:
string
=
useId
(
'
callout-label
'
);
const
descriptionId
:
string
=
useId
(
'
callout-description
'
);
const
ref
=
React
.
createRef
<
HTMLDivElement
>
();
const
[
isCalloutVisible
,
setCalloutVisible
]
=
useState
(
false
);
const
[
isShowLogDrawer
,
setShowLogDrawer
]
=
useState
(
false
);
const
onDismiss
=
useCallback
(()
=>
setCalloutVisible
(
false
),
[]);
const
showCallout
=
useCallback
(()
=>
setCalloutVisible
(
true
),
[]);
const
closeLogDrawer
=
useCallback
(()
=>
setShowLogDrawer
(
false
),
[]);
const
ShowLogDrawer
=
useCallback
(()
=>
setShowLogDrawer
(
true
),
[]);
return
(
<
div
>
<
div
className
=
'basic'
>
<
p
>
ID:
{
EXPERIMENT
.
profile
.
id
}
</
p
>
<
div
>
{
EXPERIMENT
.
profile
.
params
.
experimentName
}
</
div
>
</
div
>
<
div
className
=
'basic'
>
<
Stack
className
=
'basic'
>
<
p
>
Status
</
p
>
<
Stack
horizontal
className
=
'status'
>
<
span
className
=
{
`
${
EXPERIMENT
.
status
}
status-text`
}
>
{
EXPERIMENT
.
status
}
</
span
>
{
EXPERIMENT
.
status
===
'
ERROR
'
?
(
<
div
>
<
div
className
=
{
styles
.
buttonArea
}
ref
=
{
ref
}
>
<
IconButton
iconProps
=
{
{
iconName
:
'
info
'
}
}
onClick
=
{
isCalloutVisible
?
onDismiss
:
showCallout
}
/>
</
div
>
{
isCalloutVisible
&&
(
<
Callout
className
=
{
styles
.
callout
}
ariaLabelledBy
=
{
labelId
}
ariaDescribedBy
=
{
descriptionId
}
role
=
'alertdialog'
gapSpace
=
{
0
}
target
=
{
ref
}
onDismiss
=
{
onDismiss
}
setInitialFocus
=
{
true
}
>
<
div
className
=
{
styles
.
header
}
>
<
p
className
=
{
styles
.
title
}
id
=
{
labelId
}
>
Error
</
p
>
</
div
>
<
div
className
=
{
styles
.
inner
}
>
<
p
className
=
{
styles
.
subtext
}
id
=
{
descriptionId
}
>
{
EXPERIMENT
.
error
}
</
p
>
<
div
className
=
{
styles
.
actions
}
>
<
Link
className
=
{
styles
.
link
}
onClick
=
{
ShowLogDrawer
}
>
Learn about
</
Link
>
</
div
>
</
div
>
</
Callout
>
)
}
</
div
>
)
:
null
}
</
Stack
>
</
Stack
>
</
div
>
<
div
className
=
'basic'
>
<
BestMetricContext
.
Consumer
>
{
(
value
):
React
.
ReactNode
=>
(
<
Stack
>
<
p
>
Best metric
</
p
>
<
div
>
{
isNaN
(
value
.
bestAccuracy
)
?
'
N/A
'
:
value
.
bestAccuracy
.
toFixed
(
6
)
}
</
div
>
</
Stack
>
)
}
</
BestMetricContext
.
Consumer
>
</
div
>
<
div
className
=
'basic'
>
<
p
>
Start time
</
p
>
<
div
className
=
'nowrap'
>
{
formatTimestamp
(
EXPERIMENT
.
profile
.
startTime
)
}
</
div
>
</
div
>
<
div
className
=
'basic'
>
<
p
>
End time
</
p
>
<
div
className
=
'nowrap'
>
{
formatTimestamp
(
EXPERIMENT
.
profile
.
endTime
)
}
</
div
>
</
div
>
{
/* learn about click -> default active key is dispatcher. */
}
{
isShowLogDrawer
?
<
LogDrawer
closeDrawer
=
{
closeLogDrawer
}
activeTab
=
'dispatcher'
/>
:
null
}
</
div
>
);
};
Prev
1
2
3
4
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