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
f1105409
Unverified
Commit
f1105409
authored
Oct 15, 2020
by
liuzhe-lz
Committed by
GitHub
Oct 15, 2020
Browse files
Merge pull request #2959 from microsoft/v1.9
Merge v1.9 back to master
parents
0a6c234a
88a225f8
Changes
80
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
517 additions
and
1061 deletions
+517
-1061
azure-pipelines.yml
azure-pipelines.yml
+2
-2
src/sdk/pynni/nni/compression/torch/speedup/infer_shape.py
src/sdk/pynni/nni/compression/torch/speedup/infer_shape.py
+3
-3
src/webui/.eslintrc
src/webui/.eslintrc
+1
-0
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
-118
src/webui/src/components/buttons/Icon.tsx
src/webui/src/components/buttons/Icon.tsx
+8
-2
src/webui/src/components/modals/ChangeColumnComponent.tsx
src/webui/src/components/modals/ChangeColumnComponent.tsx
+48
-81
src/webui/src/components/modals/Compare.tsx
src/webui/src/components/modals/Compare.tsx
+143
-152
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
No files found.
azure-pipelines.yml
View file @
f1105409
...
@@ -101,9 +101,9 @@ jobs:
...
@@ -101,9 +101,9 @@ jobs:
displayName
:
'
Simple
test'
displayName
:
'
Simple
test'
-
job
:
'
macos_
1015
_python37'
-
job
:
'
macos_
latest
_python37'
pool
:
pool
:
vmImage
:
'
macOS-
10.15
'
vmImage
:
'
macOS-
latest
'
steps
:
steps
:
-
script
:
|
-
script
:
|
...
...
src/sdk/pynni/nni/compression/torch/speedup/infer_shape.py
View file @
f1105409
...
@@ -573,7 +573,7 @@ def view_inshape(module_masks, mask, shape):
...
@@ -573,7 +573,7 @@ def view_inshape(module_masks, mask, shape):
step_size
=
shape
[
'in_shape'
][
2
]
*
shape
[
'in_shape'
][
3
]
step_size
=
shape
[
'in_shape'
][
2
]
*
shape
[
'in_shape'
][
3
]
for
loc
in
mask
.
mask_index
[
1
]:
for
loc
in
mask
.
mask_index
[
1
]:
index
.
extend
([
loc
*
step_size
+
i
for
i
in
range
(
step_size
)])
index
.
extend
([
loc
*
step_size
+
i
for
i
in
range
(
step_size
)])
output_cmask
.
add_index_mask
(
dim
=
1
,
index
=
torch
.
tensor
(
index
))
# pylint: disable=not-callable
output_cmask
.
add_index_mask
(
dim
=
1
,
index
=
torch
.
tensor
(
index
)
.
to
(
mask
.
mask_index
[
1
].
device
)
)
# pylint: disable=not-callable
module_masks
.
set_output_mask
(
output_cmask
)
module_masks
.
set_output_mask
(
output_cmask
)
return
output_cmask
return
output_cmask
...
@@ -609,7 +609,7 @@ def view_outshape(module_masks, mask, shape):
...
@@ -609,7 +609,7 @@ def view_outshape(module_masks, mask, shape):
step_size
=
shape
[
'in_shape'
][
2
]
*
shape
[
'in_shape'
][
3
]
step_size
=
shape
[
'in_shape'
][
2
]
*
shape
[
'in_shape'
][
3
]
for
loc
in
mask
.
mask_index
[
1
]:
for
loc
in
mask
.
mask_index
[
1
]:
index
.
extend
([
loc
*
step_size
+
i
for
i
in
range
(
step_size
)])
index
.
extend
([
loc
*
step_size
+
i
for
i
in
range
(
step_size
)])
input_cmask
.
add_index_mask
(
dim
=
1
,
index
=
torch
.
tensor
(
index
))
# pylint: disable=not-callable
input_cmask
.
add_index_mask
(
dim
=
1
,
index
=
torch
.
tensor
(
index
)
.
to
(
mask
.
mask_index
[
1
].
device
)
)
# pylint: disable=not-callable
module_masks
.
set_input_mask
(
input_cmask
)
module_masks
.
set_input_mask
(
input_cmask
)
return
input_cmask
return
input_cmask
...
@@ -870,7 +870,7 @@ def conv2d_mask(module_masks, mask):
...
@@ -870,7 +870,7 @@ def conv2d_mask(module_masks, mask):
if
index
is
None
:
if
index
is
None
:
return
None
,
None
,
None
return
None
,
None
,
None
else
:
else
:
index
=
torch
.
LongTensor
(
index
).
to
(
weight_mask
.
device
)
index
=
index
.
long
(
).
to
(
weight_mask
.
device
)
weight_cmask
=
CoarseMask
(
num_dim
=
4
)
weight_cmask
=
CoarseMask
(
num_dim
=
4
)
weight_cmask
.
add_index_mask
(
dim
=
dim
,
index
=
index
)
weight_cmask
.
add_index_mask
(
dim
=
dim
,
index
=
index
)
bias_cmask
=
None
bias_cmask
=
None
...
...
src/webui/.eslintrc
View file @
f1105409
...
@@ -28,6 +28,7 @@
...
@@ -28,6 +28,7 @@
"@typescript-eslint/no-inferrable-types": 0,
"@typescript-eslint/no-inferrable-types": 0,
"@typescript-eslint/no-use-before-define": [2, "nofunc"],
"@typescript-eslint/no-use-before-define": [2, "nofunc"],
"@typescript-eslint/no-var-requires": 0,
"@typescript-eslint/no-var-requires": 0,
"@typescript-eslint/no-unused-vars": [2, { "argsIgnorePattern": "^_" }],
"arrow-parens": [2, "as-needed"],
"arrow-parens": [2, "as-needed"],
"no-inner-declarations": 0,
"no-inner-declarations": 0,
"no-empty": 2,
"no-empty": 2,
...
...
src/webui/src/App.scss
View file @
f1105409
...
@@ -26,9 +26,9 @@
...
@@ -26,9 +26,9 @@
}
}
.content
{
.content
{
width
:
89%
;
width
:
87%
;
min-width
:
1024px
;
margin
:
0
auto
;
margin
:
0
auto
;
min-width
:
1200px
;
margin-top
:
74px
;
margin-top
:
74px
;
margin-bottom
:
30px
;
margin-bottom
:
30px
;
}
}
...
...
src/webui/src/App.tsx
View file @
f1105409
...
@@ -4,6 +4,7 @@ import { COLUMN } from './static/const';
...
@@ -4,6 +4,7 @@ import { COLUMN } from './static/const';
import
{
EXPERIMENT
,
TRIALS
}
from
'
./static/datamodel
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
./static/datamodel
'
;
import
NavCon
from
'
./components/NavCon
'
;
import
NavCon
from
'
./components/NavCon
'
;
import
MessageInfo
from
'
./components/modals/MessageInfo
'
;
import
MessageInfo
from
'
./components/modals/MessageInfo
'
;
import
{
TrialConfigButton
}
from
'
./components/public-child/config/TrialConfigButton
'
;
import
'
./App.scss
'
;
import
'
./App.scss
'
;
interface
AppState
{
interface
AppState
{
...
@@ -30,12 +31,13 @@ export const AppContext = React.createContext({
...
@@ -30,12 +31,13 @@ export const AppContext = React.createContext({
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
changeMetricGraphMode
:
(
val
:
'
max
'
|
'
min
'
)
=>
{},
changeMetricGraphMode
:
(
val
:
'
max
'
|
'
min
'
)
=>
{},
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
// 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
>
{
class
App
extends
React
.
Component
<
{},
AppState
>
{
private
timerId
!
:
number
|
undefined
;
private
timerId
!
:
number
|
undefined
;
private
dataFormatimer
!
:
number
;
private
firstLoad
:
boolean
=
false
;
// when click refresh selector options
private
firstLoad
:
boolean
=
false
;
// when click refresh selector options
constructor
(
props
:
{})
{
constructor
(
props
:
{})
{
super
(
props
);
super
(
props
);
...
@@ -60,35 +62,8 @@ class App extends React.Component<{}, AppState> {
...
@@ -60,35 +62,8 @@ class App extends React.Component<{}, AppState> {
metricGraphMode
:
EXPERIMENT
.
optimizeMode
===
'
minimize
'
?
'
min
'
:
'
max
'
metricGraphMode
:
EXPERIMENT
.
optimizeMode
===
'
minimize
'
?
'
min
'
:
'
max
'
}));
}));
this
.
timerId
=
window
.
setTimeout
(
this
.
refresh
,
this
.
state
.
interval
*
100
);
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
=>
{
changeInterval
=
(
interval
:
number
):
void
=>
{
window
.
clearTimeout
(
this
.
timerId
);
window
.
clearTimeout
(
this
.
timerId
);
if
(
interval
===
0
)
{
if
(
interval
===
0
)
{
...
@@ -116,6 +91,12 @@ class App extends React.Component<{}, AppState> {
...
@@ -116,6 +91,12 @@ class App extends React.Component<{}, AppState> {
this
.
setState
({
bestTrialEntries
:
entries
});
this
.
setState
({
bestTrialEntries
:
entries
});
};
};
updateOverviewPage
=
():
void
=>
{
this
.
setState
(
state
=>
({
experimentUpdateBroadcast
:
state
.
experimentUpdateBroadcast
+
1
}));
};
shouldComponentUpdate
(
nextProps
:
any
,
nextState
:
AppState
):
boolean
{
shouldComponentUpdate
(
nextProps
:
any
,
nextState
:
AppState
):
boolean
{
if
(
!
(
nextState
.
isUpdate
||
nextState
.
isUpdate
===
undefined
))
{
if
(
!
(
nextState
.
isUpdate
||
nextState
.
isUpdate
===
undefined
))
{
nextState
.
isUpdate
=
true
;
nextState
.
isUpdate
=
true
;
...
@@ -155,6 +136,8 @@ class App extends React.Component<{}, AppState> {
...
@@ -155,6 +136,8 @@ class App extends React.Component<{}, AppState> {
</
div
>
</
div
>
<
Stack
className
=
'contentBox'
>
<
Stack
className
=
'contentBox'
>
<
Stack
className
=
'content'
>
<
Stack
className
=
'content'
>
{
/* search space & config */
}
<
TrialConfigButton
/>
{
/* if api has error field, show error message */
}
{
/* if api has error field, show error message */
}
{
errorList
.
map
(
{
errorList
.
map
(
(
item
,
key
)
=>
(
item
,
key
)
=>
...
@@ -179,7 +162,8 @@ class App extends React.Component<{}, AppState> {
...
@@ -179,7 +162,8 @@ class App extends React.Component<{}, AppState> {
metricGraphMode
,
metricGraphMode
,
changeMetricGraphMode
:
this
.
changeMetricGraphMode
,
changeMetricGraphMode
:
this
.
changeMetricGraphMode
,
bestTrialEntries
,
bestTrialEntries
,
changeEntries
:
this
.
changeEntries
changeEntries
:
this
.
changeEntries
,
updateOverviewPage
:
this
.
updateOverviewPage
}
}
}
}
>
>
{
this
.
props
.
children
}
{
this
.
props
.
children
}
...
...
src/webui/src/components/Overview.tsx
View file @
f1105409
import
*
as
React
from
'
react
'
;
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
{
EXPERIMENT
,
TRIALS
}
from
'
../static/datamodel
'
;
import
{
Trial
}
from
'
../static/model/trial
'
;
import
{
Trial
}
from
'
../static/model/trial
'
;
import
{
AppContext
}
from
'
../App
'
;
import
{
AppContext
}
from
'
../App
'
;
import
{
Title1
}
from
'
./overview/Title1
'
;
import
{
Title
}
from
'
./overview/Title
'
;
import
SuccessTable
from
'
./overview/SuccessTable
'
;
import
SuccessTable
from
'
./overview/table/SuccessTable
'
;
import
Progressed
from
'
./overview/Progress
'
;
import
Accuracy
from
'
./overview/Accuracy
'
;
import
Accuracy
from
'
./overview/Accuracy
'
;
import
SearchSpace
from
'
./overview/SearchSpace
'
;
import
{
ReBasicInfo
}
from
'
./overview/experiment/BasicInfo
'
;
import
{
BasicInfo
}
from
'
./overview/BasicInfo
'
;
import
{
ExpDuration
}
from
'
./overview/count/ExpDuration
'
;
import
TrialInfo
from
'
./overview/TrialProfile
'
;
import
{
ExpDurationContext
}
from
'
./overview/count/ExpDurationContext
'
;
import
'
../static/style/overview.scss
'
;
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
'
;
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
{
interface
OverviewState
{
trialConcurrency
:
number
;
trialConcurrency
:
number
;
}
}
export
const
TitleContext
=
React
.
createContext
({
export
const
BestMetricContext
=
React
.
createContext
({
text
:
''
,
bestAccuracy
:
0
icon
:
''
,
fontColor
:
''
});
});
class
Overview
extends
React
.
Component
<
{},
OverviewState
>
{
class
Overview
extends
React
.
Component
<
{},
OverviewState
>
{
static
contextType
=
AppContext
;
static
contextType
=
AppContext
;
context
!
:
React
.
ContextType
<
typeof
AppContext
>
;
constructor
(
props
)
{
constructor
(
props
)
{
super
(
props
);
super
(
props
);
...
@@ -58,11 +48,6 @@ class Overview extends React.Component<{}, OverviewState> {
...
@@ -58,11 +48,6 @@ class Overview extends React.Component<{}, OverviewState> {
changeMetricGraphMode
(
'
min
'
);
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
=>
{
updateEntries
=
(
event
:
React
.
FormEvent
<
HTMLDivElement
>
,
item
:
any
):
void
=>
{
if
(
item
!==
undefined
)
{
if
(
item
!==
undefined
)
{
this
.
context
.
changeEntries
(
item
.
key
);
this
.
context
.
changeEntries
(
item
.
key
);
...
@@ -70,118 +55,125 @@ class Overview extends React.Component<{}, OverviewState> {
...
@@ -70,118 +55,125 @@ class Overview extends React.Component<{}, OverviewState> {
};
};
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
trialConcurrency
}
=
this
.
state
;
const
bestTrials
=
this
.
findBestTrials
();
const
bestTrials
=
this
.
findBestTrials
();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const
bestAccuracy
=
bestTrials
.
length
>
0
?
bestTrials
[
0
].
accuracy
!
:
NaN
;
const
bestAccuracy
=
bestTrials
.
length
>
0
?
bestTrials
[
0
].
accuracy
!
:
NaN
;
const
accuracyGraphData
=
this
.
generateAccuracyGraph
(
bestTrials
);
const
accuracyGraphData
=
this
.
generateAccuracyGraph
(
bestTrials
);
const
noDataMessage
=
bestTrials
.
length
>
0
?
''
:
'
No data
'
;
const
noDataMessage
=
bestTrials
.
length
>
0
?
''
:
'
No data
'
;
const
maxExecDuration
=
EXPERIMENT
.
profile
.
params
.
maxExecDuration
;
const
execDuration
=
EXPERIMENT
.
profile
.
execDuration
;
return
(
return
(
<
AppContext
.
Consumer
>
<
AppContext
.
Consumer
>
{
(
value
):
React
.
ReactNode
=>
{
{
(
value
):
React
.
ReactNode
=>
{
const
{
experimentUpdateBroadcast
,
metricGraphMode
,
bestTrialEntries
}
=
value
;
const
{
metricGraphMode
,
bestTrialEntries
,
updateOverviewPage
}
=
value
;
const
titleMaxbgcolor
=
metricGraphMode
===
'
max
'
?
'
#333
'
:
'
#b3b3b3
'
;
const
maxActive
=
metricGraphMode
===
'
max
'
?
'
active
'
:
'
'
;
const
titleMinbgcolor
=
metricGraphMode
===
'
min
'
?
'
#333
'
:
'
#b3b3b3
'
;
const
minActive
=
metricGraphMode
===
'
min
'
?
'
active
'
:
'
'
;
return
(
return
(
<
div
className
=
'overview'
>
<
div
className
=
'overview'
>
{
/* status and experiment block */
}
<
div
className
=
'wrapper'
>
<
Stack
className
=
'bottomDiv bgNNI'
>
{
/* exp params */
}
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Experiment
'
,
icon
:
'
11.png
'
,
fontColor
:
''
}
}
>
<
div
className
=
'overviewBasicInfo'
>
<
Title1
/>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Experiment
'
,
icon
:
'
AutoRacing
'
}
}
>
</
TitleContext
.
Provider
>
<
Title
/>
<
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
/>
</
TitleContext
.
Provider
>
</
TitleContext
.
Provider
>
<
Stack
className
=
'experiment'
>
<
BestMetricContext
.
Provider
value
=
{
{
bestAccuracy
:
bestAccuracy
}
}
>
<
SearchSpace
searchSpace
=
{
EXPERIMENT
.
searchSpace
}
/>
<
ReBasicInfo
/>
</
Stack
>
</
BestMetricContext
.
Provider
>
</
Stack
.
Item
>
</
div
>
<
Stack
.
Item
grow
styles
=
{
{
root
:
{
width
:
450
}
}
}
className
=
'bgNNI'
>
{
/* duration & trial numbers */
}
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Config
'
,
icon
:
'
4.png
'
,
fontColor
:
''
}
}
>
<
div
className
=
'overviewProgress'
>
<
Title1
/>
<
div
className
=
'duration'
>
</
TitleContext
.
Provider
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Duration
'
,
icon
:
'
Timer
'
}
}
>
<
Stack
className
=
'experiment'
>
<
Title
/>
{
/* 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
/>
</
TitleContext
.
Provider
>
</
TitleContext
.
Provider
>
</
div
>
<
ExpDurationContext
.
Provider
<
div
className
=
'title minTitle'
onClick
=
{
this
.
clickMinTop
}
>
value
=
{
{
maxExecDuration
,
execDuration
,
updateOverviewPage
}
}
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Top minimal trials
'
,
icon
:
'
min.png
'
,
fontColor
:
titleMinbgcolor
}
}
>
>
<
Title1
/>
<
ExpDuration
/>
</
TitleContext
.
Provider
>
</
ExpDurationContext
.
Provider
>
</
div
>
<
div
style
=
{
{
position
:
'
absolute
'
,
right
:
'
2%
'
,
top
:
8
}
}
>
<
Dropdown
selectedKey
=
{
bestTrialEntries
}
options
=
{
entriesOption
}
onChange
=
{
this
.
updateEntries
}
styles
=
{
{
root
:
{
width
:
170
}
}
}
/>
</
div
>
</
div
>
</
Stack
>
<
div
className
=
'empty'
/>
<
Stack
horizontal
tokens
=
{
stackTokens
}
>
<
div
className
=
'trialCount'
>
<
div
style
=
{
{
width
:
'
40%
'
,
position
:
'
relative
'
}
}
>
<
TitleContext
.
Provider
value
=
{
{
text
:
'
Trial numbers
'
,
icon
:
'
NumberSymbol
'
}
}
>
<
Accuracy
<
Title
/>
accuracyData
=
{
accuracyGraphData
}
</
TitleContext
.
Provider
>
accNodata
=
{
noDataMessage
}
<
ExpDurationContext
.
Provider
height
=
{
404
}
value
=
{
{
maxExecDuration
,
execDuration
,
updateOverviewPage
}
}
/>
>
</
div
>
<
TrialCount
/>
<
div
style
=
{
{
width
:
'
60%
'
}
}
>
</
ExpDurationContext
.
Provider
>
<
SuccessTable
trialIds
=
{
bestTrials
.
map
(
trial
=>
trial
.
info
.
id
)
}
/>
</
div
>
</
div
>
</
Stack
>
</
div
>
</
Stack
>
{
/* 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
>
</
div
>
);
);
}
}
}
}
...
...
src/webui/src/components/TrialsDetail.tsx
View file @
f1105409
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Stack
,
StackItem
,
Pivot
,
PivotItem
,
Dropdown
,
IDropdownOption
,
DefaultButton
}
from
'
@fluentui/react
'
;
import
{
Stack
,
Pivot
,
PivotItem
}
from
'
@fluentui/react
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../static/datamodel
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../static/datamodel
'
;
import
{
Trial
}
from
'
../static/model/trial
'
;
import
{
AppContext
}
from
'
../App
'
;
import
{
AppContext
}
from
'
../App
'
;
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
Para
from
'
./trial-detail/Para
'
;
import
Para
from
'
./trial-detail/Para
'
;
...
@@ -12,22 +10,13 @@ import TableList from './trial-detail/TableList';
...
@@ -12,22 +10,13 @@ import TableList from './trial-detail/TableList';
import
'
../static/style/trialsDetail.scss
'
;
import
'
../static/style/trialsDetail.scss
'
;
import
'
../static/style/search.scss
'
;
import
'
../static/style/search.scss
'
;
const
searchOptions
=
[
{
key
:
'
id
'
,
text
:
'
Id
'
},
{
key
:
'
Trial No.
'
,
text
:
'
Trial No.
'
},
{
key
:
'
status
'
,
text
:
'
Status
'
},
{
key
:
'
parameters
'
,
text
:
'
Parameters
'
}
];
interface
TrialDetailState
{
interface
TrialDetailState
{
tablePageSize
:
number
;
// table components val
whichChart
:
string
;
whichChart
:
string
;
searchType
:
string
;
searchFilter
:
(
trial
:
Trial
)
=>
boolean
;
}
}
class
TrialsDetail
extends
React
.
Component
<
{},
TrialDetailState
>
{
class
TrialsDetail
extends
React
.
Component
<
{},
TrialDetailState
>
{
static
contextType
=
AppContext
;
static
contextType
=
AppContext
;
context
!
:
React
.
ContextType
<
typeof
AppContext
>
;
public
interAccuracy
=
0
;
public
interAccuracy
=
0
;
public
interAllTableList
=
2
;
public
interAllTableList
=
2
;
...
@@ -37,71 +26,22 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
...
@@ -37,71 +26,22 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
constructor
(
props
)
{
constructor
(
props
)
{
super
(
props
);
super
(
props
);
this
.
state
=
{
this
.
state
=
{
tablePageSize
:
20
,
whichChart
:
'
Default metric
'
whichChart
:
'
Default metric
'
,
searchType
:
'
id
'
,
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/explicit-function-return-type
searchFilter
:
trial
=>
true
};
};
}
}
// search a trial by trial No. | trial id | Parameters | Status
searchTrial
=
(
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
):
void
=>
{
const
targetValue
=
event
.
target
.
value
;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let
filter
=
(
trial
:
Trial
):
boolean
=>
true
;
if
(
!
targetValue
.
trim
())
{
this
.
setState
({
searchFilter
:
filter
});
return
;
}
switch
(
this
.
state
.
searchType
)
{
case
'
id
'
:
filter
=
(
trial
):
boolean
=>
trial
.
info
.
id
.
toUpperCase
().
includes
(
targetValue
.
toUpperCase
());
break
;
case
'
Trial No.
'
:
filter
=
(
trial
):
boolean
=>
trial
.
info
.
sequenceId
.
toString
()
===
targetValue
;
break
;
case
'
status
'
:
filter
=
(
trial
):
boolean
=>
trial
.
info
.
status
.
toUpperCase
().
includes
(
targetValue
.
toUpperCase
());
break
;
case
'
parameters
'
:
// TODO: support filters like `x: 2` (instead of `"x": 2`)
filter
=
(
trial
):
boolean
=>
JSON
.
stringify
(
trial
.
info
.
hyperParameters
,
null
,
4
).
includes
(
targetValue
);
break
;
default
:
alert
(
`Unexpected search filter
${
this
.
state
.
searchType
}
`
);
}
this
.
setState
({
searchFilter
:
filter
});
};
handleTablePageSizeSelect
=
(
event
:
React
.
FormEvent
<
HTMLDivElement
>
,
item
:
IDropdownOption
|
undefined
):
void
=>
{
if
(
item
!==
undefined
)
{
this
.
setState
({
tablePageSize
:
item
.
text
===
'
all
'
?
-
1
:
parseInt
(
item
.
text
,
10
)
});
}
};
handleWhichTabs
=
(
item
:
any
):
void
=>
{
handleWhichTabs
=
(
item
:
any
):
void
=>
{
this
.
setState
({
whichChart
:
item
.
props
.
headerText
});
this
.
setState
({
whichChart
:
item
.
props
.
headerText
});
};
};
updateSearchFilterType
=
(
event
:
React
.
FormEvent
<
HTMLDivElement
>
,
item
:
IDropdownOption
|
undefined
):
void
=>
{
// clear input value and re-render table
if
(
item
!==
undefined
)
{
if
(
this
.
searchInput
!==
null
)
{
this
.
searchInput
.
value
=
''
;
}
this
.
setState
(()
=>
({
searchType
:
item
.
key
.
toString
()
}));
}
};
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
tablePageSize
,
whichChart
,
searchType
}
=
this
.
state
;
const
{
whichChart
}
=
this
.
state
;
const
source
=
TRIALS
.
filter
(
this
.
state
.
searchFilter
);
const
source
=
TRIALS
.
toArray
(
);
const
trialIds
=
TRIALS
.
filter
(
this
.
state
.
searchFilter
).
map
(
trial
=>
trial
.
id
);
const
trialIds
=
TRIALS
.
toArray
(
).
map
(
trial
=>
trial
.
id
);
return
(
return
(
<
AppContext
.
Consumer
>
<
AppContext
.
Consumer
>
{
(
value
):
React
.
ReactNode
=>
(
{
(
_
value
):
React
.
ReactNode
=>
(
<
React
.
Fragment
>
<
React
.
Fragment
>
<
div
className
=
'trial'
id
=
'tabsty'
>
<
div
className
=
'trial'
id
=
'tabsty'
>
<
Pivot
<
Pivot
...
@@ -143,59 +83,9 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
...
@@ -143,59 +83,9 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
</
div
>
</
div
>
{
/* trial table list */
}
{
/* trial table list */
}
<
div
style
=
{
{
backgroundColor
:
'
#fff
'
}
}
>
<
div
style
=
{
{
backgroundColor
:
'
#fff
'
}
}
>
<
Stack
horizontal
className
=
'panelTitle'
style
=
{
{
marginTop
:
10
}
}
>
<
span
style
=
{
{
marginRight
:
12
}
}
>
{
tableListIcon
}
</
span
>
<
span
>
Trial jobs
</
span
>
</
Stack
>
<
Stack
horizontal
className
=
'allList'
>
<
StackItem
grow
=
{
50
}
>
<
DefaultButton
text
=
'Compare'
className
=
'allList-compare'
// use child-component tableList's function, the function is in child-component.
onClick
=
{
():
void
=>
{
if
(
this
.
tableList
)
{
this
.
tableList
.
compareBtn
();
}
}
}
/>
</
StackItem
>
<
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
}
tableSource
=
{
source
}
tableSource
=
{
source
.
map
(
trial
=>
trial
.
tableRecord
)
}
columnList
=
{
value
.
columnList
}
changeColumn
=
{
value
.
changeColumn
}
trialsUpdateBroadcast
=
{
this
.
context
.
trialsUpdateBroadcast
}
trialsUpdateBroadcast
=
{
this
.
context
.
trialsUpdateBroadcast
}
// TODO: change any to specific type
ref
=
{
(
tabList
):
any
=>
(
this
.
tableList
=
tabList
)
}
/>
/>
</
div
>
</
div
>
</
React
.
Fragment
>
</
React
.
Fragment
>
...
...
src/webui/src/components/buttons/Icon.tsx
View file @
f1105409
...
@@ -11,11 +11,14 @@ const copy = <Icon iconName='Copy' />;
...
@@ -11,11 +11,14 @@ const copy = <Icon iconName='Copy' />;
const
tableListIcon
=
<
Icon
iconName
=
'BulletedList'
/>;
const
tableListIcon
=
<
Icon
iconName
=
'BulletedList'
/>;
const
downLoadIcon
=
{
iconName
:
'
Download
'
};
const
downLoadIcon
=
{
iconName
:
'
Download
'
};
const
infoIconAbout
=
{
iconName
:
'
info
'
};
const
infoIconAbout
=
{
iconName
:
'
info
'
};
const
timeIcon
=
{
iconName
:
'
Re
fresh
'
};
const
timeIcon
=
{
iconName
:
'
Re
minderTime
'
};
const
disableUpdates
=
{
iconName
:
'
DisableUpdates
'
};
const
disableUpdates
=
{
iconName
:
'
DisableUpdates
'
};
const
requency
=
{
iconName
:
'
Timer
'
};
const
requency
=
{
iconName
:
'
Timer
'
};
const
closeTimer
=
{
iconName
:
'
Blocked2
'
};
const
closeTimer
=
{
iconName
:
'
Blocked2
'
};
const
LineChart
=
<
Icon
iconName
=
'LineChart'
/>;
const
LineChart
=
<
Icon
iconName
=
'LineChart'
/>;
const
Edit
=
<
Icon
iconName
=
'Edit'
/>;
const
CheckMark
=
<
Icon
iconName
=
'CheckMark'
/>;
const
Cancel
=
<
Icon
iconName
=
'Cancel'
/>;
export
{
export
{
infoIcon
,
infoIcon
,
...
@@ -31,5 +34,8 @@ export {
...
@@ -31,5 +34,8 @@ export {
disableUpdates
,
disableUpdates
,
requency
,
requency
,
closeTimer
,
closeTimer
,
LineChart
LineChart
,
Edit
,
CheckMark
,
Cancel
};
};
src/webui/src/components/modals/ChangeColumnComponent.tsx
View file @
f1105409
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
Dialog
,
DialogType
,
DialogFooter
,
Checkbox
,
PrimaryButton
,
DefaultButton
}
from
'
@fluentui/react
'
;
import
{
Dialog
,
DialogType
,
DialogFooter
,
Checkbox
,
PrimaryButton
,
DefaultButton
}
from
'
@fluentui/react
'
;
import
{
OPERATION
}
from
'
../../static/const
'
;
interface
ChangeColumnState
{
interface
ChangeColumnState
{
userSelectColumnList
:
string
[];
// buffer, not saved yet
originSelectColumnList
:
string
[];
currentSelected
:
string
[];
}
}
interface
ChangeColumnProps
{
interface
ChangeColumnProps
{
isHideDialog
:
boolean
;
allColumns
:
SimpleColumn
[];
// all column List
showColumn
:
string
[];
// all column List
selectedColumns
:
string
[];
// user selected column list
selectedColumn
:
string
[];
// user selected column list
onSelectedChange
:
(
val
:
string
[])
=>
void
;
changeColumn
:
(
val
:
string
[])
=>
void
;
onHideDialog
:
()
=>
void
;
hideShowColumnDialog
:
()
=>
void
;
minSelected
?:
number
;
}
interface
SimpleColumn
{
key
:
string
;
// key for management
name
:
string
;
// name to display
}
}
interface
CheckBoxItems
{
interface
CheckBoxItems
{
...
@@ -20,12 +24,12 @@ interface CheckBoxItems {
...
@@ -20,12 +24,12 @@ interface CheckBoxItems {
checked
:
boolean
;
checked
:
boolean
;
onChange
:
()
=>
void
;
onChange
:
()
=>
void
;
}
}
class
ChangeColumnComponent
extends
React
.
Component
<
ChangeColumnProps
,
ChangeColumnState
>
{
class
ChangeColumnComponent
extends
React
.
Component
<
ChangeColumnProps
,
ChangeColumnState
>
{
constructor
(
props
:
ChangeColumnProps
)
{
constructor
(
props
:
ChangeColumnProps
)
{
super
(
props
);
super
(
props
);
this
.
state
=
{
this
.
state
=
{
userSelectColumnList
:
this
.
props
.
selectedColumn
,
currentSelected
:
this
.
props
.
selectedColumns
originSelectColumnList
:
this
.
props
.
selectedColumn
};
};
}
}
...
@@ -38,97 +42,50 @@ class ChangeColumnComponent extends React.Component<ChangeColumnProps, ChangeCol
...
@@ -38,97 +42,50 @@ class ChangeColumnComponent extends React.Component<ChangeColumnProps, ChangeCol
label
:
string
,
label
:
string
,
val
?:
boolean
val
?:
boolean
):
void
=>
{
):
void
=>
{
const
source
:
string
[]
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
state
.
userSelectColumnList
))
;
const
source
:
string
[]
=
[...
this
.
state
.
currentSelected
]
;
if
(
val
===
true
)
{
if
(
val
===
true
)
{
if
(
!
source
.
includes
(
label
))
{
if
(
!
source
.
includes
(
label
))
{
source
.
push
(
label
);
source
.
push
(
label
);
this
.
setState
(
()
=>
({
userSelectColumnList
:
source
})
)
;
this
.
setState
(
{
currentSelected
:
source
});
}
}
}
else
{
}
else
{
if
(
source
.
includes
(
label
))
{
// remove from source
// remove from source
const
result
=
source
.
filter
(
item
=>
item
!==
label
);
const
result
=
source
.
filter
(
item
=>
item
!==
label
);
this
.
setState
({
currentSelected
:
result
});
this
.
setState
(()
=>
({
userSelectColumnList
:
result
}));
}
}
}
};
};
saveUserSelectColumn
=
():
void
=>
{
saveUserSelectColumn
=
():
void
=>
{
const
{
userSelectColumnList
}
=
this
.
state
;
const
{
currentSelected
}
=
this
.
state
;
const
{
showColumn
}
=
this
.
props
;
const
{
allColumns
,
onSelectedChange
}
=
this
.
props
;
// sort by Trial No. | ID | Duration | Start Time | End Time | ...
const
selectedColumns
=
allColumns
.
map
(
column
=>
column
.
key
).
filter
(
key
=>
currentSelected
.
includes
(
key
));
const
sortColumn
:
string
[]
=
[];
onSelectedChange
(
selectedColumns
);
/**
this
.
hideDialog
();
*
* TODO: use this function to refactor sort column
* search space might orderless
showColumn.map(item => {
userSelectColumnList.map(key => {
if (item === key || key.includes('search space')) {
if (!sortColumn.includes(key)) {
sortColumn.push(key);
}
}
});
});
*/
// push ![Operation] ![search space] column
showColumn
.
map
(
item
=>
{
userSelectColumnList
.
map
(
key
=>
{
if
(
item
===
key
&&
item
!==
OPERATION
)
{
sortColumn
.
push
(
key
);
}
});
});
// push search space key
userSelectColumnList
.
map
(
index
=>
{
if
(
index
.
includes
(
'
search space
'
))
{
if
(
!
sortColumn
.
includes
(
index
))
{
sortColumn
.
push
(
index
);
}
}
});
// push Operation
if
(
userSelectColumnList
.
includes
(
OPERATION
))
{
sortColumn
.
push
(
OPERATION
);
}
this
.
props
.
changeColumn
(
sortColumn
);
this
.
hideDialog
();
// hide dialog
};
hideDialog
=
():
void
=>
{
this
.
props
.
hideShowColumnDialog
();
};
};
// user exit dialog
// user exit dialog
cancelOption
=
():
void
=>
{
cancelOption
=
():
void
=>
{
// reset select column
// reset select column
const
{
originSelectColumnList
}
=
this
.
state
;
this
.
setState
({
currentSelected
:
this
.
props
.
selectedColumns
},
()
=>
{
this
.
setState
({
userSelectColumnList
:
originSelectColumnList
},
()
=>
{
this
.
hideDialog
();
this
.
hideDialog
();
});
});
};
};
private
hideDialog
=
():
void
=>
{
this
.
props
.
onHideDialog
();
};
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
showColumn
,
isHideDialog
}
=
this
.
props
;
const
{
allColumns
,
minSelected
}
=
this
.
props
;
const
{
userSelectColumnList
}
=
this
.
state
;
const
{
currentSelected
}
=
this
.
state
;
const
renderOptions
:
Array
<
CheckBoxItems
>
=
[];
showColumn
.
map
(
item
=>
{
if
(
userSelectColumnList
.
includes
(
item
))
{
// selected column name
renderOptions
.
push
({
label
:
item
,
checked
:
true
,
onChange
:
this
.
makeChangeHandler
(
item
)
});
}
else
{
renderOptions
.
push
({
label
:
item
,
checked
:
false
,
onChange
:
this
.
makeChangeHandler
(
item
)
});
}
});
return
(
return
(
<
div
>
<
div
>
<
Dialog
<
Dialog
hidden
=
{
isHideDialog
}
// required field!
hidden
=
{
false
}
dialogContentProps
=
{
{
dialogContentProps
=
{
{
type
:
DialogType
.
largeHeader
,
type
:
DialogType
.
largeHeader
,
title
:
'
C
hange tabl
e column
'
,
title
:
'
C
ustomiz
e column
s
'
,
subText
:
'
You can chose which columns you w
ant
to see
in the table
.
'
subText
:
'
You can cho
o
se which columns you w
ish
to see.
'
}
}
}
}
modalProps
=
{
{
modalProps
=
{
{
isBlocking
:
false
,
isBlocking
:
false
,
...
@@ -136,12 +93,22 @@ class ChangeColumnComponent extends React.Component<ChangeColumnProps, ChangeCol
...
@@ -136,12 +93,22 @@ class ChangeColumnComponent extends React.Component<ChangeColumnProps, ChangeCol
}
}
}
}
>
>
<
div
className
=
'columns-height'
>
<
div
className
=
'columns-height'
>
{
renderOptions
.
map
(
item
=>
{
{
allColumns
.
map
(
item
=>
(
return
<
Checkbox
key
=
{
item
.
label
}
{
...
item
}
styles
=
{
{
root
:
{
marginBottom
:
8
}
}
}
/>;
<
Checkbox
})
}
key
=
{
item
.
key
}
label
=
{
item
.
name
}
checked
=
{
currentSelected
.
includes
(
item
.
key
)
}
onChange
=
{
this
.
makeChangeHandler
(
item
.
key
)
}
styles
=
{
{
root
:
{
marginBottom
:
8
}
}
}
/>
))
}
</
div
>
</
div
>
<
DialogFooter
>
<
DialogFooter
>
<
PrimaryButton
text
=
'Save'
onClick
=
{
this
.
saveUserSelectColumn
}
/>
<
PrimaryButton
text
=
'Save'
onClick
=
{
this
.
saveUserSelectColumn
}
disabled
=
{
currentSelected
.
length
<
(
minSelected
===
undefined
?
1
:
minSelected
)
}
/>
<
DefaultButton
text
=
'Cancel'
onClick
=
{
this
.
cancelOption
}
/>
<
DefaultButton
text
=
'Cancel'
onClick
=
{
this
.
cancelOption
}
/>
</
DialogFooter
>
</
DialogFooter
>
</
Dialog
>
</
Dialog
>
...
...
src/webui/src/components/modals/Compare.tsx
View file @
f1105409
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
import
{
renderToString
}
from
'
react-dom/server
'
;
import
{
Stack
,
Modal
,
IconButton
,
IDragOptions
,
ContextualMenu
}
from
'
@fluentui/react
'
;
import
{
Stack
,
Modal
,
IconButton
,
IDragOptions
,
ContextualMenu
}
from
'
@fluentui/react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
IntermediateVal
from
'
../public-child/IntermediateVal
'
;
import
{
TooltipForIntermediate
,
TableObj
,
SingleAxis
}
from
'
../../static/interface
'
;
import
{
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
TableRecord
,
Intermedia
,
TooltipForIntermediate
}
from
'
../../static/interface
'
;
import
{
contentStyles
,
iconButtonStyles
}
from
'
../buttons/ModalTheme
'
;
import
{
contentStyles
,
iconButtonStyles
}
from
'
../buttons/ModalTheme
'
;
import
'
../../static/style/compare.scss
'
;
import
'
../../static/style/compare.scss
'
;
import
{
convertDuration
,
parseMetrics
}
from
'
../../static/function
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
function
_getWebUIWidth
():
number
{
return
window
.
innerWidth
;
}
const
dragOptions
:
IDragOptions
=
{
const
dragOptions
:
IDragOptions
=
{
moveMenuItemText
:
'
Move
'
,
moveMenuItemText
:
'
Move
'
,
...
@@ -13,79 +18,81 @@ const dragOptions: IDragOptions = {
...
@@ -13,79 +18,81 @@ const dragOptions: IDragOptions = {
menu
:
ContextualMenu
menu
:
ContextualMenu
};
};
// the modal of trial compare
// TODO: this should be refactored to the common modules
// copied from trial.ts
function
_parseIntermediates
(
trial
:
TableObj
):
number
[]
{
const
intermediates
:
number
[]
=
[];
for
(
const
metric
of
trial
.
intermediates
)
{
if
(
metric
===
undefined
)
{
break
;
}
const
parsedMetric
=
parseMetrics
(
metric
.
data
);
if
(
typeof
parsedMetric
===
'
object
'
)
{
// TODO: should handle more types of metric keys
intermediates
.
push
(
parsedMetric
.
default
);
}
else
{
intermediates
.
push
(
parsedMetric
);
}
}
return
intermediates
;
}
interface
Item
{
id
:
string
;
sequenceId
:
number
;
duration
:
string
;
parameters
:
Map
<
string
,
any
>
;
metrics
:
Map
<
string
,
any
>
;
intermediates
:
number
[];
}
interface
CompareProps
{
interface
CompareProps
{
compareStacks
:
Array
<
TableRecord
>
;
trials
:
TableObj
[];
cancelFunc
:
()
=>
void
;
title
:
string
;
showDetails
:
boolean
;
onHideDialog
:
()
=>
void
;
}
}
class
Compare
extends
React
.
Component
<
CompareProps
,
{}
>
{
class
Compare
extends
React
.
Component
<
CompareProps
,
{}
>
{
public
_isCompareMount
!
:
boolean
;
constructor
(
props
:
CompareProps
)
{
constructor
(
props
:
CompareProps
)
{
super
(
props
);
super
(
props
);
}
}
intermediate
=
():
React
.
ReactNode
=>
{
private
_generateTooltipSummary
(
row
:
Item
,
metricKey
:
string
):
string
{
const
{
compareStacks
}
=
this
.
props
;
return
renderToString
(
const
trialIntermediate
:
Array
<
Intermedia
>
=
[];
<
div
className
=
'tooldetailAccuracy'
>
const
idsList
:
string
[]
=
[];
<
div
>
Trial ID:
{
row
.
id
}
</
div
>
compareStacks
.
forEach
(
element
=>
{
<
div
>
Default metric:
{
row
.
metrics
.
get
(
metricKey
)
||
'
N/A
'
}
</
div
>
const
trial
=
TRIALS
.
getTrial
(
element
.
id
);
</
div
>
trialIntermediate
.
push
({
);
name
:
element
.
id
,
}
data
:
trial
.
description
.
intermediate
,
type
:
'
line
'
,
private
_intermediates
(
items
:
Item
[],
metricKey
:
string
):
React
.
ReactNode
{
hyperPara
:
trial
.
description
.
parameters
// Precondition: make sure `items` is not empty
});
const
xAxisMax
=
Math
.
max
(...
items
.
map
(
item
=>
item
.
intermediates
.
length
));
idsList
.
push
(
element
.
id
);
const
xAxis
=
Array
(
xAxisMax
)
});
.
fill
(
0
)
// find max intermediate number
.
map
((
_
,
i
)
=>
i
+
1
);
// [1, 2, 3, ..., xAxisMax]
trialIntermediate
.
sort
((
a
,
b
)
=>
{
const
dataForEchart
=
items
.
map
(
item
=>
({
return
b
.
data
.
length
-
a
.
data
.
length
;
name
:
item
.
id
,
});
data
:
item
.
intermediates
,
const
legend
:
string
[]
=
[];
type
:
'
line
'
// max length
}));
const
length
=
trialIntermediate
[
0
]
!==
undefined
?
trialIntermediate
[
0
].
data
.
length
:
0
;
const
legend
=
dataForEchart
.
map
(
item
=>
item
.
name
);
const
xAxis
:
number
[]
=
[];
trialIntermediate
.
forEach
(
element
=>
{
legend
.
push
(
element
.
name
);
});
for
(
let
i
=
1
;
i
<=
length
;
i
++
)
{
xAxis
.
push
(
i
);
}
const
option
=
{
const
option
=
{
tooltip
:
{
tooltip
:
{
trigger
:
'
item
'
,
trigger
:
'
item
'
,
enterable
:
true
,
enterable
:
true
,
position
:
function
(
point
:
number
[],
data
:
TooltipForIntermediate
):
number
[]
{
position
:
(
point
:
number
[],
data
:
TooltipForIntermediate
):
[
number
,
number
]
=>
{
if
(
data
.
dataIndex
<
length
/
2
)
{
if
(
data
.
dataIndex
<
length
/
2
)
{
return
[
point
[
0
],
80
];
return
[
point
[
0
],
80
];
}
else
{
}
else
{
return
[
point
[
0
]
-
300
,
80
];
return
[
point
[
0
]
-
300
,
80
];
}
}
},
},
formatter
:
function
(
data
:
TooltipForIntermediate
):
React
.
ReactNode
{
formatter
:
(
data
:
TooltipForIntermediate
):
string
=>
{
const
trialId
=
data
.
seriesName
;
const
item
=
items
.
find
(
k
=>
k
.
id
===
data
.
seriesName
)
as
Item
;
let
obj
=
{};
return
this
.
_generateTooltipSummary
(
item
,
metricKey
);
const
temp
=
trialIntermediate
.
find
(
key
=>
key
.
name
===
trialId
);
if
(
temp
!==
undefined
)
{
obj
=
temp
.
hyperPara
;
}
return
(
'
<div class="tooldetailAccuracy">
'
+
'
<div>Trial ID:
'
+
trialId
+
'
</div>
'
+
'
<div>Intermediate:
'
+
data
.
data
+
'
</div>
'
+
'
<div>Parameters:
'
+
'
<pre>
'
+
JSON
.
stringify
(
obj
,
null
,
4
)
+
'
</pre>
'
+
'
</div>
'
+
'
</div>
'
);
}
}
},
},
grid
:
{
grid
:
{
...
@@ -96,12 +103,11 @@ class Compare extends React.Component<CompareProps, {}> {
...
@@ -96,12 +103,11 @@ class Compare extends React.Component<CompareProps, {}> {
legend
:
{
legend
:
{
type
:
'
scroll
'
,
type
:
'
scroll
'
,
right
:
40
,
right
:
40
,
left
:
idsList
.
length
>
6
?
80
:
null
,
left
:
legend
.
length
>
6
?
80
:
null
,
data
:
idsList
data
:
legend
},
},
xAxis
:
{
xAxis
:
{
type
:
'
category
'
,
type
:
'
category
'
,
// name: '# Intermediate',
boundaryGap
:
false
,
boundaryGap
:
false
,
data
:
xAxis
data
:
xAxis
},
},
...
@@ -110,7 +116,7 @@ class Compare extends React.Component<CompareProps, {}> {
...
@@ -110,7 +116,7 @@ class Compare extends React.Component<CompareProps, {}> {
name
:
'
Metric
'
,
name
:
'
Metric
'
,
scale
:
true
scale
:
true
},
},
series
:
trialIntermediate
series
:
dataForEchart
};
};
return
(
return
(
<
ReactEcharts
<
ReactEcharts
...
@@ -119,108 +125,92 @@ class Compare extends React.Component<CompareProps, {}> {
...
@@ -119,108 +125,92 @@ class Compare extends React.Component<CompareProps, {}> {
notMerge
=
{
true
}
// update now
notMerge
=
{
true
}
// update now
/>
/>
);
);
};
}
// render table column ---
initColumn
=
():
React
.
ReactNode
=>
{
const
idList
:
string
[]
=
[];
const
sequenceIdList
:
number
[]
=
[];
const
durationList
:
number
[]
=
[];
const
compareStacks
=
this
.
props
.
compareStacks
.
map
(
tableRecord
=>
TRIALS
.
getTrial
(
tableRecord
.
id
));
private
_renderRow
(
key
:
string
,
rowName
:
string
,
className
:
string
,
items
:
Item
[],
formatter
:
(
item
:
Item
)
=>
string
):
React
.
ReactNode
{
return
(
<
tr
key
=
{
key
}
>
<
td
className
=
'column'
>
{
rowName
}
</
td
>
{
items
.
map
(
item
=>
(
<
td
className
=
{
className
}
key
=
{
item
.
id
}
>
{
formatter
(
item
)
}
</
td
>
))
}
</
tr
>
);
}
const
parameterList
:
Array
<
object
>
=
[];
private
_overlapKeys
(
s
:
Map
<
string
,
any
>
[]):
string
[]
{
let
parameterKeys
:
string
[]
=
[];
// Calculate the overlapped keys for multiple
if
(
compareStacks
.
length
!==
0
)
{
const
intersection
:
string
[]
=
[];
parameterKeys
=
Object
.
keys
(
compareStacks
[
0
].
description
.
parameters
);
for
(
const
i
of
s
[
0
].
keys
())
{
}
let
inAll
=
true
;
compareStacks
.
forEach
(
temp
=>
{
for
(
const
t
of
s
)
{
idList
.
push
(
temp
.
id
);
if
(
!
Array
.
from
(
t
.
keys
()).
includes
(
i
))
{
sequenceIdList
.
push
(
temp
.
sequenceId
)
;
inAll
=
false
;
durationList
.
push
(
temp
.
duration
)
;
break
;
parameterList
.
push
(
temp
.
description
.
parameters
);
}
});
}
let
isComplexSearchSpace
;
if
(
inAll
)
{
i
f
(
parameterList
.
length
>
0
)
{
i
ntersection
.
push
(
i
);
isComplexSearchSpace
=
typeof
parameterList
[
0
][
parameterKeys
[
0
]]
===
'
object
'
?
true
:
false
;
}
}
}
const
width
=
this
.
getWebUIWidth
();
return
intersection
;
let
scrollClass
;
}
// render table column ---
private
_columns
(
items
:
Item
[]):
React
.
ReactNode
{
// Precondition: make sure `items` is not empty
const
width
=
_getWebUIWidth
();
let
scrollClass
:
string
=
''
;
if
(
width
>
1200
)
{
if
(
width
>
1200
)
{
scrollClass
=
i
dList
.
length
>
3
?
'
flex
'
:
''
;
scrollClass
=
i
tems
.
length
>
3
?
'
flex
'
:
''
;
}
else
if
(
width
<
700
)
{
}
else
if
(
width
<
700
)
{
scrollClass
=
i
dList
.
length
>
1
?
'
flex
'
:
''
;
scrollClass
=
i
tems
.
length
>
1
?
'
flex
'
:
''
;
}
else
{
}
else
{
scrollClass
=
i
dList
.
length
>
2
?
'
flex
'
:
''
;
scrollClass
=
i
tems
.
length
>
2
?
'
flex
'
:
''
;
}
}
const
parameterKeys
=
this
.
_overlapKeys
(
items
.
map
(
item
=>
item
.
parameters
));
const
metricKeys
=
this
.
_overlapKeys
(
items
.
map
(
item
=>
item
.
metrics
));
return
(
return
(
<
table
className
=
{
`compare-modal-table
${
scrollClass
}
`
}
>
<
table
className
=
{
`compare-modal-table
${
scrollClass
}
`
}
>
<
tbody
>
<
tbody
>
<
tr
>
{
this
.
_renderRow
(
'
id
'
,
'
ID
'
,
'
value idList
'
,
items
,
item
=>
item
.
id
)
}
<
td
className
=
'column'
>
Id
</
td
>
{
this
.
_renderRow
(
'
trialnum
'
,
'
Trial No.
'
,
'
value
'
,
items
,
item
=>
item
.
sequenceId
.
toString
())
}
{
Object
.
keys
(
idList
).
map
(
key
=>
(
{
this
.
_renderRow
(
'
duration
'
,
'
Duration
'
,
'
value
'
,
items
,
item
=>
item
.
duration
)
}
<
td
className
=
'value idList'
key
=
{
key
}
>
{
parameterKeys
.
map
(
k
=>
{
idList
[
key
]
}
this
.
_renderRow
(
`space_
${
k
}
`
,
k
,
'
value
'
,
items
,
item
=>
item
.
parameters
.
get
(
k
))
</
td
>
)
}
))
}
{
metricKeys
.
map
(
k
=>
</
tr
>
this
.
_renderRow
(
`metrics_
${
k
}
`
,
`Metric:
${
k
}
`
,
'
value
'
,
items
,
item
=>
item
.
metrics
.
get
(
k
))
<
tr
>
)
}
<
td
className
=
'column'
>
Trial No.
</
td
>
{
Object
.
keys
(
sequenceIdList
).
map
(
key
=>
(
<
td
className
=
'value idList'
key
=
{
key
}
>
{
sequenceIdList
[
key
]
}
</
td
>
))
}
</
tr
>
<
tr
>
<
td
className
=
'column'
>
Default metric
</
td
>
{
Object
.
keys
(
compareStacks
).
map
(
index
=>
(
<
td
className
=
'value'
key
=
{
index
}
>
<
IntermediateVal
trialId
=
{
compareStacks
[
index
].
id
}
/>
</
td
>
))
}
</
tr
>
<
tr
>
<
td
className
=
'column'
>
duration
</
td
>
{
Object
.
keys
(
durationList
).
map
(
index
=>
(
<
td
className
=
'value'
key
=
{
index
}
>
{
durationList
[
index
]
}
</
td
>
))
}
</
tr
>
{
isComplexSearchSpace
?
null
:
Object
.
keys
(
parameterKeys
).
map
(
index
=>
(
<
tr
key
=
{
index
}
>
<
td
className
=
'column'
key
=
{
index
}
>
{
parameterKeys
[
index
]
}
</
td
>
{
Object
.
keys
(
parameterList
).
map
(
key
=>
(
<
td
key
=
{
key
}
className
=
'value'
>
{
parameterList
[
key
][
parameterKeys
[
index
]]
}
</
td
>
))
}
</
tr
>
))
}
</
tbody
>
</
tbody
>
</
table
>
</
table
>
);
);
};
getWebUIWidth
=
():
number
=>
{
return
window
.
innerWidth
;
};
componentDidMount
():
void
{
this
.
_isCompareMount
=
true
;
}
componentWillUnmount
():
void
{
this
.
_isCompareMount
=
false
;
}
}
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
cancelFunc
}
=
this
.
props
;
const
{
onHideDialog
,
trials
,
title
,
showDetails
}
=
this
.
props
;
const
flatten
=
(
m
:
Map
<
SingleAxis
,
any
>
):
Map
<
string
,
any
>
=>
{
return
new
Map
(
Array
.
from
(
m
).
map
(([
key
,
value
])
=>
[
key
.
baseName
,
value
]));
};
const
inferredSearchSpace
=
TRIALS
.
inferredSearchSpace
(
EXPERIMENT
.
searchSpaceNew
);
const
items
:
Item
[]
=
trials
.
map
(
trial
=>
({
id
:
trial
.
id
,
sequenceId
:
trial
.
sequenceId
,
duration
:
convertDuration
(
trial
.
duration
),
parameters
:
flatten
(
trial
.
parameters
(
inferredSearchSpace
)),
metrics
:
flatten
(
trial
.
metrics
(
TRIALS
.
inferredMetricSpace
())),
intermediates
:
_parseIntermediates
(
trial
)
}));
const
metricKeys
=
this
.
_overlapKeys
(
items
.
map
(
item
=>
item
.
metrics
));
const
defaultMetricKey
=
!
metricKeys
||
metricKeys
.
includes
(
'
default
'
)
?
'
default
'
:
metricKeys
[
0
];
return
(
return
(
<
Modal
<
Modal
...
@@ -229,22 +219,23 @@ class Compare extends React.Component<CompareProps, {}> {
...
@@ -229,22 +219,23 @@ class Compare extends React.Component<CompareProps, {}> {
className
=
'compare-modal'
className
=
'compare-modal'
allowTouchBodyScroll
=
{
true
}
allowTouchBodyScroll
=
{
true
}
dragOptions
=
{
dragOptions
}
dragOptions
=
{
dragOptions
}
onDismiss
=
{
onHideDialog
}
>
>
<
div
>
<
div
>
<
div
className
=
{
contentStyles
.
header
}
>
<
div
className
=
{
contentStyles
.
header
}
>
<
span
>
Compare trials
</
span
>
<
span
>
{
title
}
</
span
>
<
IconButton
<
IconButton
styles
=
{
iconButtonStyles
}
styles
=
{
iconButtonStyles
}
iconProps
=
{
{
iconName
:
'
Cancel
'
}
}
iconProps
=
{
{
iconName
:
'
Cancel
'
}
}
ariaLabel
=
'Close popup modal'
ariaLabel
=
'Close popup modal'
onClick
=
{
cancelFunc
}
onClick
=
{
onHideDialog
}
/>
/>
</
div
>
</
div
>
<
Stack
className
=
'compare-modal-intermediate'
>
<
Stack
className
=
'compare-modal-intermediate'
>
{
this
.
intermediate
(
)
}
{
this
.
_
intermediate
s
(
items
,
defaultMetricKey
)
}
<
Stack
className
=
'compare-yAxis'
>
# Intermediate result
</
Stack
>
<
Stack
className
=
'compare-yAxis'
>
# Intermediate result
</
Stack
>
</
Stack
>
</
Stack
>
<
Stack
>
{
this
.
initColumn
(
)
}
</
Stack
>
{
showDetails
&&
<
Stack
>
{
this
.
_columns
(
items
)
}
</
Stack
>
}
</
div
>
</
div
>
</
Modal
>
</
Modal
>
);
);
...
...
src/webui/src/components/overview/Accuracy.tsx
View file @
f1105409
...
@@ -22,7 +22,7 @@ class Accuracy extends React.Component<AccuracyProps, {}> {
...
@@ -22,7 +22,7 @@ class Accuracy extends React.Component<AccuracyProps, {}> {
render
():
React
.
ReactNode
{
render
():
React
.
ReactNode
{
const
{
accNodata
,
accuracyData
,
height
}
=
this
.
props
;
const
{
accNodata
,
accuracyData
,
height
}
=
this
.
props
;
return
(
return
(
<
div
>
<
div
style
=
{
{
position
:
'
relative
'
}
}
>
<
ReactEcharts
<
ReactEcharts
option
=
{
accuracyData
}
option
=
{
accuracyData
}
style
=
{
{
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 @
f1105409
import
*
as
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
Stack
}
from
'
@fluentui/react
'
;
import
{
Stack
,
Icon
,
initializeIcons
}
from
'
@fluentui/react
'
;
import
{
TitleContext
}
from
'
../Overview
'
;
import
{
TitleContext
}
from
'
./TitleContext
'
;
import
'
../../static/style/overviewTitle.scss
'
;
import
'
../../static/style/overview/overviewTitle.scss
'
;
initializeIcons
();
export
const
Title
1
=
():
any
=>
(
export
const
Title
=
():
any
=>
(
<
TitleContext
.
Consumer
>
<
TitleContext
.
Consumer
>
{
(
value
):
React
.
ReactNode
=>
(
{
(
value
):
React
.
ReactNode
=>
(
<
Stack
horizontal
className
=
'panelTitle'
>
<
Stack
horizontal
className
=
'panelTitle'
>
<
img
src
=
{
require
(
`../../static/img/icon/
${
value
.
icon
}
`
)
}
alt
=
'icon'
/>
<
Icon
iconName
=
{
value
.
icon
}
/>
<
span
style
=
{
{
color
:
value
.
fontColor
}
}
>
{
value
.
text
}
</
span
>
<
span
>
{
value
.
text
}
</
span
>
</
Stack
>
</
Stack
>
)
}
)
}
</
TitleContext
.
Consumer
>
</
TitleContext
.
Consumer
>
...
...
src/webui/src/components/overview/TitleContext.tsx
0 → 100644
View file @
f1105409
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 @
f1105409
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
>
);
};
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