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
4bbffd17
Commit
4bbffd17
authored
Jul 17, 2019
by
suiguoxin
Browse files
Merge branch 'master' of
git://github.com/microsoft/nni
parents
d92c69f4
4592ba41
Changes
87
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
878 additions
and
301 deletions
+878
-301
docs/en_US/training_services.rst
docs/en_US/training_services.rst
+5
-5
docs/en_US/tuners.rst
docs/en_US/tuners.rst
+3
-3
docs/en_US/tutorials.rst
docs/en_US/tutorials.rst
+9
-8
src/sdk/pynni/nni/__main__.py
src/sdk/pynni/nni/__main__.py
+0
-2
src/sdk/pynni/nni/bohb_advisor/bohb_advisor.py
src/sdk/pynni/nni/bohb_advisor/bohb_advisor.py
+106
-46
src/sdk/pynni/nni/hyperband_advisor/hyperband_advisor.py
src/sdk/pynni/nni/hyperband_advisor/hyperband_advisor.py
+60
-38
src/sdk/pynni/nni/msg_dispatcher.py
src/sdk/pynni/nni/msg_dispatcher.py
+6
-5
src/sdk/pynni/nni/utils.py
src/sdk/pynni/nni/utils.py
+8
-0
src/webui/src/App.css
src/webui/src/App.css
+1
-0
src/webui/src/components/Modal/ExperimentDrawer.tsx
src/webui/src/components/Modal/ExperimentDrawer.tsx
+144
-0
src/webui/src/components/Modal/LogDrawer.tsx
src/webui/src/components/Modal/LogDrawer.tsx
+206
-0
src/webui/src/components/SlideBar.tsx
src/webui/src/components/SlideBar.tsx
+111
-186
src/webui/src/components/overview/Progress.tsx
src/webui/src/components/overview/Progress.tsx
+24
-3
src/webui/src/components/public-child/MonacoEditor.tsx
src/webui/src/components/public-child/MonacoEditor.tsx
+50
-0
src/webui/src/static/const.ts
src/webui/src/static/const.ts
+6
-1
src/webui/src/static/function.ts
src/webui/src/static/function.ts
+23
-1
src/webui/src/static/style/button.scss
src/webui/src/static/style/button.scss
+1
-0
src/webui/src/static/style/compare.scss
src/webui/src/static/style/compare.scss
+2
-2
src/webui/src/static/style/control.scss
src/webui/src/static/style/control.scss
+1
-1
src/webui/src/static/style/logDrawer.scss
src/webui/src/static/style/logDrawer.scss
+112
-0
No files found.
docs/en_US/training_services.rst
View file @
4bbffd17
...
...
@@ -2,8 +2,8 @@ Introduction to NNI Training Services
=====================================
.. toctree::
Local<LocalMode>
Remote<RemoteMachineMode>
OpenPAI<PaiMode>
Kubeflow<KubeflowMode>
FrameworkController<FrameworkControllerMode>
\ No newline at end of file
Local<./TrainingService/LocalMode>
Remote<./TrainingService/RemoteMachineMode>
OpenPAI<./TrainingService/PaiMode>
Kubeflow<./TrainingService/KubeflowMode>
FrameworkController<./TrainingService/FrameworkControllerMode>
\ No newline at end of file
docs/en_US/tuners.rst
View file @
4bbffd17
...
...
@@ -13,6 +13,6 @@ For details, please refer to the following tutorials:
.. toctree::
:maxdepth: 2
Builtin Tuners<BuiltinTuner>
Customized Tuners<CustomizeTuner>
Customized Advisor<CustomizeAdvisor>
\ No newline at end of file
Builtin Tuners <builtin_tuner>
Customized Tuners <Tuner/CustomizeTuner>
Customized Advisor <Tuner/CustomizeAdvisor>
docs/en_US/tutorials.rst
View file @
4bbffd17
...
...
@@ -5,12 +5,13 @@ Tutorials
.. toctree::
:maxdepth: 2
Installation
Write Trial
<
Trials>
Tuners<tuners>
Assessors<assessors>
WebUI
Training Platform<training_services>
How to use docker
<
HowToUseDocker>
Installation
<Tutorial/Installation>
Write Trial
<TrialExample/
Trials>
Tuners
<tuners>
Assessors
<assessors>
WebUI
<Tutorial/WebUI>
Training Platform
<training_services>
How to use docker
<Tutorial/
HowToUseDocker>
advanced
Debug HowTo<HowToDebug>
\ No newline at end of file
Debug HowTo <Tutorial/HowToDebug>
NNI on Windows <Tutorial/NniOnWindows>
\ No newline at end of file
src/sdk/pynni/nni/__main__.py
View file @
4bbffd17
...
...
@@ -130,8 +130,6 @@ def main():
if
args
.
advisor_class_name
:
# advisor is enabled and starts to run
if
args
.
multi_phase
:
raise
AssertionError
(
'multi_phase has not been supported in advisor'
)
if
args
.
advisor_class_name
in
AdvisorModuleName
:
dispatcher
=
create_builtin_class_instance
(
args
.
advisor_class_name
,
...
...
src/sdk/pynni/nni/bohb_advisor/bohb_advisor.py
View file @
4bbffd17
...
...
@@ -31,7 +31,8 @@ import ConfigSpace.hyperparameters as CSH
from
nni.protocol
import
CommandType
,
send
from
nni.msg_dispatcher_base
import
MsgDispatcherBase
from
nni.utils
import
OptimizeMode
,
extract_scalar_reward
,
randint_to_quniform
from
nni.utils
import
OptimizeMode
,
MetricType
,
extract_scalar_reward
,
randint_to_quniform
from
nni.common
import
multi_phase_enabled
from
.config_generator
import
CG_BOHB
...
...
@@ -79,7 +80,7 @@ def create_bracket_parameter_id(brackets_id, brackets_curr_decay, increased_id=-
return
params_id
class
Bracket
():
class
Bracket
(
object
):
"""
A bracket in BOHB, all the information of a bracket is managed by
an instance of this class.
...
...
@@ -329,11 +330,12 @@ class BOHB(MsgDispatcherBase):
# config generator
self
.
cg
=
None
def
load_checkpoint
(
self
):
pass
def
save_checkpoint
(
self
):
pass
# record the latest parameter_id of the trial job trial_job_id.
# if there is no running parameter_id, self.job_id_para_id_map[trial_job_id] == None
# new trial job is added to this dict and finished trial job is removed from it.
self
.
job_id_para_id_map
=
dict
()
# record the unsatisfied parameter request from trial jobs
self
.
unsatisfied_jobs
=
[]
def
handle_initialize
(
self
,
data
):
"""Initialize Tuner, including creating Bayesian optimization-based parametric models
...
...
@@ -399,7 +401,7 @@ class BOHB(MsgDispatcherBase):
for
_
in
range
(
self
.
credit
):
self
.
_request_one_trial_job
()
def
_
reques
t_one_trial_job
(
self
):
def
_
ge
t_one_trial_job
(
self
):
"""get one trial job, i.e., one hyperparameter configuration.
If this function is called, Command will be sent by BOHB:
...
...
@@ -423,7 +425,7 @@ class BOHB(MsgDispatcherBase):
'parameters'
:
''
}
send
(
CommandType
.
NoMoreTrialJobs
,
json_tricks
.
dumps
(
ret
))
return
return
None
assert
self
.
generated_hyper_configs
params
=
self
.
generated_hyper_configs
.
pop
()
ret
=
{
...
...
@@ -432,6 +434,27 @@ class BOHB(MsgDispatcherBase):
'parameters'
:
params
[
1
]
}
self
.
parameters
[
params
[
0
]]
=
params
[
1
]
return
ret
def
_request_one_trial_job
(
self
):
"""get one trial job, i.e., one hyperparameter configuration.
If this function is called, Command will be sent by BOHB:
a. If there is a parameter need to run, will return "NewTrialJob" with a dict:
{
'parameter_id': id of new hyperparameter
'parameter_source': 'algorithm'
'parameters': value of new hyperparameter
}
b. If BOHB don't have parameter waiting, will return "NoMoreTrialJobs" with
{
'parameter_id': '-1_0_0',
'parameter_source': 'algorithm',
'parameters': ''
}
"""
ret
=
self
.
_get_one_trial_job
()
if
ret
is
not
None
:
send
(
CommandType
.
NewTrialJob
,
json_tricks
.
dumps
(
ret
))
self
.
credit
-=
1
...
...
@@ -502,23 +525,38 @@ class BOHB(MsgDispatcherBase):
hyper_params: the hyperparameters (a string) generated and returned by tuner
"""
logger
.
debug
(
'Tuner handle trial end, result is %s'
,
data
)
hyper_params
=
json_tricks
.
loads
(
data
[
'hyper_params'
])
s
,
i
,
_
=
hyper_params
[
'parameter_id'
].
split
(
'_'
)
self
.
_handle_trial_end
(
hyper_params
[
'parameter_id'
])
if
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
:
del
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
def
_send_new_trial
(
self
):
while
self
.
unsatisfied_jobs
:
ret
=
self
.
_get_one_trial_job
()
if
ret
is
None
:
break
one_unsatisfied
=
self
.
unsatisfied_jobs
.
pop
(
0
)
ret
[
'trial_job_id'
]
=
one_unsatisfied
[
'trial_job_id'
]
ret
[
'parameter_index'
]
=
one_unsatisfied
[
'parameter_index'
]
# update parameter_id in self.job_id_para_id_map
self
.
job_id_para_id_map
[
ret
[
'trial_job_id'
]]
=
ret
[
'parameter_id'
]
send
(
CommandType
.
SendTrialJobParameter
,
json_tricks
.
dumps
(
ret
))
for
_
in
range
(
self
.
credit
):
self
.
_request_one_trial_job
()
def
_handle_trial_end
(
self
,
parameter_id
):
s
,
i
,
_
=
parameter_id
.
split
(
'_'
)
hyper_configs
=
self
.
brackets
[
int
(
s
)].
inform_trial_end
(
int
(
i
))
if
hyper_configs
is
not
None
:
logger
.
debug
(
'bracket %s next round %s, hyper_configs: %s'
,
s
,
i
,
hyper_configs
)
self
.
generated_hyper_configs
=
self
.
generated_hyper_configs
+
hyper_configs
for
_
in
range
(
self
.
credit
):
self
.
_request_one_trial_job
()
# Finish this bracket and generate a new bracket
elif
self
.
brackets
[
int
(
s
)].
no_more_trial
:
self
.
curr_s
-=
1
self
.
generate_new_bracket
()
for
_
in
range
(
self
.
credit
):
self
.
_request_one_trial_job
()
self
.
_send_new_trial
()
def
handle_report_metric_data
(
self
,
data
):
"""reveice the metric data and update Bayesian optimization with final result
...
...
@@ -535,6 +573,22 @@ class BOHB(MsgDispatcherBase):
"""
logger
.
debug
(
'handle report metric data = %s'
,
data
)
if
data
[
'type'
]
==
MetricType
.
REQUEST_PARAMETER
:
assert
multi_phase_enabled
()
assert
data
[
'trial_job_id'
]
is
not
None
assert
data
[
'parameter_index'
]
is
not
None
assert
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
self
.
_handle_trial_end
(
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]])
ret
=
self
.
_get_one_trial_job
()
if
ret
is
None
:
self
.
unsatisfied_jobs
.
append
({
'trial_job_id'
:
data
[
'trial_job_id'
],
'parameter_index'
:
data
[
'parameter_index'
]})
else
:
ret
[
'trial_job_id'
]
=
data
[
'trial_job_id'
]
ret
[
'parameter_index'
]
=
data
[
'parameter_index'
]
# update parameter_id in self.job_id_para_id_map
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
=
ret
[
'parameter_id'
]
send
(
CommandType
.
SendTrialJobParameter
,
json_tricks
.
dumps
(
ret
))
else
:
assert
'value'
in
data
value
=
extract_scalar_reward
(
data
[
'value'
])
if
self
.
optimize_mode
is
OptimizeMode
.
Maximize
:
...
...
@@ -543,12 +597,18 @@ class BOHB(MsgDispatcherBase):
reward
=
value
assert
'parameter_id'
in
data
s
,
i
,
_
=
data
[
'parameter_id'
].
split
(
'_'
)
logger
.
debug
(
'bracket id = %s, metrics value = %s, type = %s'
,
s
,
value
,
data
[
'type'
])
s
=
int
(
s
)
# add <trial_job_id, parameter_id> to self.job_id_para_id_map here,
# because when the first parameter_id is created, trial_job_id is not known yet.
if
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
:
assert
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
==
data
[
'parameter_id'
]
else
:
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
=
data
[
'parameter_id'
]
assert
'type'
in
data
if
data
[
'type'
]
==
'
FINAL
'
:
if
data
[
'type'
]
==
MetricType
.
FINAL
:
# and PERIODICAL metric are independent, thus, not comparable.
assert
'sequence'
in
data
self
.
brackets
[
s
].
set_config_perf
(
...
...
@@ -559,7 +619,7 @@ class BOHB(MsgDispatcherBase):
_parameters
.
pop
(
_KEY
)
# update BO with loss, max_s budget, hyperparameters
self
.
cg
.
new_result
(
loss
=
reward
,
budget
=
data
[
'sequence'
],
parameters
=
_parameters
,
update_model
=
True
)
elif
data
[
'type'
]
==
'
PERIODICAL
'
:
elif
data
[
'type'
]
==
MetricType
.
PERIODICAL
:
self
.
brackets
[
s
].
set_config_perf
(
int
(
i
),
data
[
'parameter_id'
],
data
[
'sequence'
],
value
)
else
:
...
...
src/sdk/pynni/nni/hyperband_advisor/hyperband_advisor.py
View file @
4bbffd17
...
...
@@ -30,8 +30,8 @@ import json_tricks
from
nni.protocol
import
CommandType
,
send
from
nni.msg_dispatcher_base
import
MsgDispatcherBase
from
nni.common
import
init_logger
from
nni.utils
import
NodeType
,
OptimizeMode
,
extract_scalar_reward
,
randint_to_quniform
from
nni.common
import
init_logger
,
multi_phase_enabled
from
nni.utils
import
NodeType
,
OptimizeMode
,
MetricType
,
extract_scalar_reward
,
randint_to_quniform
import
nni.parameter_expressions
as
parameter_expressions
_logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -277,7 +277,7 @@ class Hyperband(MsgDispatcherBase):
optimize_mode: str
optimize mode, 'maximize' or 'minimize'
"""
def
__init__
(
self
,
R
,
eta
=
3
,
optimize_mode
=
'maximize'
):
def
__init__
(
self
,
R
=
60
,
eta
=
3
,
optimize_mode
=
'maximize'
):
"""B = (s_max + 1)R"""
super
(
Hyperband
,
self
).
__init__
()
self
.
R
=
R
# pylint: disable=invalid-name
...
...
@@ -296,11 +296,10 @@ class Hyperband(MsgDispatcherBase):
# In this case, tuner increases self.credit to issue a trial config sometime later.
self
.
credit
=
0
def
load_checkpoint
(
self
):
pass
def
save_checkpoint
(
self
):
pass
# record the latest parameter_id of the trial job trial_job_id.
# if there is no running parameter_id, self.job_id_para_id_map[trial_job_id] == None
# new trial job is added to this dict and finished trial job is removed from it.
self
.
job_id_para_id_map
=
dict
()
def
handle_initialize
(
self
,
data
):
"""data is search space
...
...
@@ -321,9 +320,10 @@ class Hyperband(MsgDispatcherBase):
number of trial jobs
"""
for
_
in
range
(
data
):
self
.
_request_one_trial_job
()
ret
=
self
.
_get_one_trial_job
()
send
(
CommandType
.
NewTrialJob
,
json_tricks
.
dumps
(
ret
))
def
_
reques
t_one_trial_job
(
self
):
def
_
ge
t_one_trial_job
(
self
):
"""get one trial job, i.e., one hyperparameter configuration."""
if
not
self
.
generated_hyper_configs
:
if
self
.
curr_s
<
0
:
...
...
@@ -346,7 +346,8 @@ class Hyperband(MsgDispatcherBase):
'parameter_source'
:
'algorithm'
,
'parameters'
:
params
[
1
]
}
send
(
CommandType
.
NewTrialJob
,
json_tricks
.
dumps
(
ret
))
return
ret
def
handle_update_search_space
(
self
,
data
):
"""data: JSON object, which is search space
...
...
@@ -360,6 +361,18 @@ class Hyperband(MsgDispatcherBase):
randint_to_quniform
(
self
.
searchspace_json
)
self
.
random_state
=
np
.
random
.
RandomState
()
def
_handle_trial_end
(
self
,
parameter_id
):
"""
Parameters
----------
parameter_id: parameter id of the finished config
"""
bracket_id
,
i
,
_
=
parameter_id
.
split
(
'_'
)
hyper_configs
=
self
.
brackets
[
int
(
bracket_id
)].
inform_trial_end
(
int
(
i
))
if
hyper_configs
is
not
None
:
_logger
.
debug
(
'bracket %s next round %s, hyper_configs: %s'
,
bracket_id
,
i
,
hyper_configs
)
self
.
generated_hyper_configs
=
self
.
generated_hyper_configs
+
hyper_configs
def
handle_trial_end
(
self
,
data
):
"""
Parameters
...
...
@@ -371,22 +384,9 @@ class Hyperband(MsgDispatcherBase):
hyper_params: the hyperparameters (a string) generated and returned by tuner
"""
hyper_params
=
json_tricks
.
loads
(
data
[
'hyper_params'
])
bracket_id
,
i
,
_
=
hyper_params
[
'parameter_id'
].
split
(
'_'
)
hyper_configs
=
self
.
brackets
[
int
(
bracket_id
)].
inform_trial_end
(
int
(
i
))
if
hyper_configs
is
not
None
:
_logger
.
debug
(
'bracket %s next round %s, hyper_configs: %s'
,
bracket_id
,
i
,
hyper_configs
)
self
.
generated_hyper_configs
=
self
.
generated_hyper_configs
+
hyper_configs
for
_
in
range
(
self
.
credit
):
if
not
self
.
generated_hyper_configs
:
break
params
=
self
.
generated_hyper_configs
.
pop
()
ret
=
{
'parameter_id'
:
params
[
0
],
'parameter_source'
:
'algorithm'
,
'parameters'
:
params
[
1
]
}
send
(
CommandType
.
NewTrialJob
,
json_tricks
.
dumps
(
ret
))
self
.
credit
-=
1
self
.
_handle_trial_end
(
hyper_params
[
'parameter_id'
])
if
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
:
del
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
def
handle_report_metric_data
(
self
,
data
):
"""
...
...
@@ -400,15 +400,37 @@ class Hyperband(MsgDispatcherBase):
ValueError
Data type not supported
"""
if
data
[
'type'
]
==
MetricType
.
REQUEST_PARAMETER
:
assert
multi_phase_enabled
()
assert
data
[
'trial_job_id'
]
is
not
None
assert
data
[
'parameter_index'
]
is
not
None
assert
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
self
.
_handle_trial_end
(
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]])
ret
=
self
.
_get_one_trial_job
()
if
data
[
'trial_job_id'
]
is
not
None
:
ret
[
'trial_job_id'
]
=
data
[
'trial_job_id'
]
if
data
[
'parameter_index'
]
is
not
None
:
ret
[
'parameter_index'
]
=
data
[
'parameter_index'
]
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
=
ret
[
'parameter_id'
]
send
(
CommandType
.
SendTrialJobParameter
,
json_tricks
.
dumps
(
ret
))
else
:
value
=
extract_scalar_reward
(
data
[
'value'
])
bracket_id
,
i
,
_
=
data
[
'parameter_id'
].
split
(
'_'
)
bracket_id
=
int
(
bracket_id
)
if
data
[
'type'
]
==
'FINAL'
:
# add <trial_job_id, parameter_id> to self.job_id_para_id_map here,
# because when the first parameter_id is created, trial_job_id is not known yet.
if
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
:
assert
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
==
data
[
'parameter_id'
]
else
:
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
=
data
[
'parameter_id'
]
if
data
[
'type'
]
==
MetricType
.
FINAL
:
# sys.maxsize indicates this value is from FINAL metric data, because data['sequence'] from FINAL metric
# and PERIODICAL metric are independent, thus, not comparable.
self
.
brackets
[
bracket_id
].
set_config_perf
(
int
(
i
),
data
[
'parameter_id'
],
sys
.
maxsize
,
value
)
self
.
completed_hyper_configs
.
append
(
data
)
elif
data
[
'type'
]
==
'
PERIODICAL
'
:
elif
data
[
'type'
]
==
MetricType
.
PERIODICAL
:
self
.
brackets
[
bracket_id
].
set_config_perf
(
int
(
i
),
data
[
'parameter_id'
],
data
[
'sequence'
],
value
)
else
:
raise
ValueError
(
'Data type not supported: {}'
.
format
(
data
[
'type'
]))
...
...
src/sdk/pynni/nni/msg_dispatcher.py
View file @
4bbffd17
...
...
@@ -27,6 +27,7 @@ from .msg_dispatcher_base import MsgDispatcherBase
from
.assessor
import
AssessResult
from
.common
import
multi_thread_enabled
,
multi_phase_enabled
from
.env_vars
import
dispatcher_env_vars
from
.utils
import
MetricType
_logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -133,12 +134,12 @@ class MsgDispatcher(MsgDispatcherBase):
- 'value': metric value reported by nni.report_final_result()
- 'type': report type, support {'FINAL', 'PERIODICAL'}
"""
if
data
[
'type'
]
==
'
FINAL
'
:
if
data
[
'type'
]
==
MetricType
.
FINAL
:
self
.
_handle_final_metric_data
(
data
)
elif
data
[
'type'
]
==
'
PERIODICAL
'
:
elif
data
[
'type'
]
==
MetricType
.
PERIODICAL
:
if
self
.
assessor
is
not
None
:
self
.
_handle_intermediate_metric_data
(
data
)
elif
data
[
'type'
]
==
'
REQUEST_PARAMETER
'
:
elif
data
[
'type'
]
==
MetricType
.
REQUEST_PARAMETER
:
assert
multi_phase_enabled
()
assert
data
[
'trial_job_id'
]
is
not
None
assert
data
[
'parameter_index'
]
is
not
None
...
...
@@ -183,7 +184,7 @@ class MsgDispatcher(MsgDispatcherBase):
def
_handle_intermediate_metric_data
(
self
,
data
):
"""Call assessor to process intermediate results
"""
if
data
[
'type'
]
!=
'
PERIODICAL
'
:
if
data
[
'type'
]
!=
MetricType
.
PERIODICAL
:
return
if
self
.
assessor
is
None
:
return
...
...
@@ -224,7 +225,7 @@ class MsgDispatcher(MsgDispatcherBase):
trial is early stopped.
"""
_logger
.
debug
(
'Early stop notify tuner data: [%s]'
,
data
)
data
[
'type'
]
=
'
FINAL
'
data
[
'type'
]
=
MetricType
.
FINAL
if
multi_thread_enabled
():
self
.
_handle_final_metric_data
(
data
)
else
:
...
...
src/sdk/pynni/nni/utils.py
View file @
4bbffd17
...
...
@@ -51,6 +51,14 @@ class NodeType:
NAME
=
'_name'
class
MetricType
:
"""The types of metric data
"""
FINAL
=
'FINAL'
PERIODICAL
=
'PERIODICAL'
REQUEST_PARAMETER
=
'REQUEST_PARAMETER'
def
split_index
(
params
):
"""
Delete index infromation from params
...
...
src/webui/src/App.css
View file @
4bbffd17
.nni
{
font-family
:
'Segoe UI'
,
Tahoma
,
Geneva
,
Verdana
,
sans-serif
;
color
:
#212121
;
font-size
:
14px
;
background
:
#f2f2f2
;
...
...
src/webui/src/components/Modal/ExperimentDrawer.tsx
0 → 100644
View file @
4bbffd17
import
*
as
React
from
'
react
'
;
import
axios
from
'
axios
'
;
import
{
downFile
}
from
'
../../static/function
'
;
import
{
Drawer
,
Tabs
,
Row
,
Col
,
Button
}
from
'
antd
'
;
import
{
MANAGER_IP
,
DRAWEROPTION
}
from
'
../../static/const
'
;
import
MonacoEditor
from
'
react-monaco-editor
'
;
const
{
TabPane
}
=
Tabs
;
import
'
../../static/style/logDrawer.scss
'
;
interface
ExpDrawerProps
{
isVisble
:
boolean
;
closeExpDrawer
:
()
=>
void
;
}
interface
ExpDrawerState
{
experiment
:
string
;
}
class
ExperimentDrawer
extends
React
.
Component
<
ExpDrawerProps
,
ExpDrawerState
>
{
public
_isCompareMount
:
boolean
;
constructor
(
props
:
ExpDrawerProps
)
{
super
(
props
);
this
.
state
=
{
experiment
:
''
};
}
getExperimentContent
=
()
=>
{
axios
.
all
([
axios
.
get
(
`
${
MANAGER_IP
}
/experiment`
),
axios
.
get
(
`
${
MANAGER_IP
}
/trial-jobs`
),
axios
.
get
(
`
${
MANAGER_IP
}
/metric-data`
)
])
.
then
(
axios
.
spread
((
res
,
res1
,
res2
)
=>
{
if
(
res
.
status
===
200
&&
res1
.
status
===
200
&&
res2
.
status
===
200
)
{
if
(
res
.
data
.
params
.
searchSpace
)
{
res
.
data
.
params
.
searchSpace
=
JSON
.
parse
(
res
.
data
.
params
.
searchSpace
);
}
let
trialMessagesArr
=
res1
.
data
;
const
interResultList
=
res2
.
data
;
Object
.
keys
(
trialMessagesArr
).
map
(
item
=>
{
// transform hyperparameters as object to show elegantly
trialMessagesArr
[
item
].
hyperParameters
=
JSON
.
parse
(
trialMessagesArr
[
item
].
hyperParameters
);
const
trialId
=
trialMessagesArr
[
item
].
id
;
// add intermediate result message
trialMessagesArr
[
item
].
intermediate
=
[];
Object
.
keys
(
interResultList
).
map
(
key
=>
{
const
interId
=
interResultList
[
key
].
trialJobId
;
if
(
trialId
===
interId
)
{
trialMessagesArr
[
item
].
intermediate
.
push
(
interResultList
[
key
]);
}
});
});
const
result
=
{
experimentParameters
:
res
.
data
,
trialMessage
:
trialMessagesArr
};
if
(
this
.
_isCompareMount
===
true
)
{
this
.
setState
(()
=>
({
experiment
:
JSON
.
stringify
(
result
,
null
,
4
)
}));
}
}
}));
}
downExperimentParameters
=
()
=>
{
const
{
experiment
}
=
this
.
state
;
downFile
(
experiment
,
'
experiment.json
'
);
}
componentDidMount
()
{
this
.
_isCompareMount
=
true
;
this
.
getExperimentContent
();
}
componentWillReceiveProps
(
nextProps
:
ExpDrawerProps
)
{
const
{
isVisble
}
=
nextProps
;
if
(
isVisble
===
true
)
{
this
.
getExperimentContent
();
}
}
componentWillUnmount
()
{
this
.
_isCompareMount
=
false
;
}
render
()
{
const
{
isVisble
,
closeExpDrawer
}
=
this
.
props
;
const
{
experiment
}
=
this
.
state
;
const
heights
:
number
=
window
.
innerHeight
-
48
;
return
(
<
Row
className
=
"logDrawer"
>
<
Drawer
// title="Log Message"
placement
=
"right"
closable
=
{
false
}
destroyOnClose
=
{
true
}
onClose
=
{
closeExpDrawer
}
visible
=
{
isVisble
}
width
=
"54%"
height
=
{
heights
}
>
<
div
className
=
"card-container log-tab-body"
style
=
{
{
height
:
heights
}
}
>
<
Tabs
type
=
"card"
>
<
TabPane
tab
=
"Experiment Parameters"
key
=
"Experiment"
>
<
div
className
=
"just-for-log"
>
<
MonacoEditor
width
=
"100%"
height
=
{
heights
*
0.9
}
language
=
"json"
value
=
{
experiment
}
options
=
{
DRAWEROPTION
}
/>
</
div
>
<
Row
className
=
"buttons"
>
<
Col
span
=
{
12
}
>
<
Button
type
=
"primary"
onClick
=
{
this
.
downExperimentParameters
}
>
Download
</
Button
>
</
Col
>
<
Col
span
=
{
12
}
className
=
"close"
>
<
Button
type
=
"default"
onClick
=
{
closeExpDrawer
}
>
Close
</
Button
>
</
Col
>
</
Row
>
</
TabPane
>
</
Tabs
>
</
div
>
</
Drawer
>
</
Row
>
);
}
}
export
default
ExperimentDrawer
;
src/webui/src/components/Modal/LogDrawer.tsx
0 → 100644
View file @
4bbffd17
import
*
as
React
from
'
react
'
;
import
axios
from
'
axios
'
;
import
{
Drawer
,
Tabs
,
Row
,
Col
,
Button
,
Icon
}
from
'
antd
'
;
import
{
DOWNLOAD_IP
}
from
'
../../static/const
'
;
import
{
downFile
}
from
'
../../static/function
'
;
const
{
TabPane
}
=
Tabs
;
import
MonacoHTML
from
'
../public-child/MonacoEditor
'
;
import
'
../../static/style/logDrawer.scss
'
;
interface
LogDrawerProps
{
isVisble
:
boolean
;
closeDrawer
:
()
=>
void
;
activeTab
?:
string
;
}
interface
LogDrawerState
{
nniManagerLogStr
:
string
;
dispatcherLogStr
:
string
;
isLoading
:
boolean
;
isLoadispatcher
:
boolean
;
}
class
LogDrawer
extends
React
.
Component
<
LogDrawerProps
,
LogDrawerState
>
{
public
_isLogDrawer
:
boolean
;
constructor
(
props
:
LogDrawerProps
)
{
super
(
props
);
this
.
state
=
{
nniManagerLogStr
:
'
nnimanager
'
,
dispatcherLogStr
:
'
dispatcher
'
,
isLoading
:
false
,
isLoadispatcher
:
false
};
}
getNNImanagerLogmessage
=
()
=>
{
if
(
this
.
_isLogDrawer
===
true
)
{
this
.
setState
({
isLoading
:
true
},
()
=>
{
axios
(
`
${
DOWNLOAD_IP
}
/nnimanager.log`
,
{
method
:
'
GET
'
})
.
then
(
res
=>
{
if
(
res
.
status
===
200
)
{
setTimeout
(()
=>
{
this
.
setNNImanager
(
res
.
data
);
},
300
);
}
});
});
}
}
setDispatcher
=
(
value
:
string
)
=>
{
if
(
this
.
_isLogDrawer
===
true
)
{
this
.
setState
(()
=>
({
isLoadispatcher
:
false
,
dispatcherLogStr
:
value
}));
}
}
setNNImanager
=
(
val
:
string
)
=>
{
if
(
this
.
_isLogDrawer
===
true
)
{
this
.
setState
(()
=>
({
isLoading
:
false
,
nniManagerLogStr
:
val
}));
}
}
getdispatcherLogmessage
=
()
=>
{
if
(
this
.
_isLogDrawer
===
true
)
{
this
.
setState
({
isLoadispatcher
:
true
},
()
=>
{
axios
(
`
${
DOWNLOAD_IP
}
/dispatcher.log`
,
{
method
:
'
GET
'
})
.
then
(
res
=>
{
if
(
res
.
status
===
200
)
{
setTimeout
(()
=>
{
this
.
setDispatcher
(
res
.
data
);
},
300
);
}
});
});
}
}
downloadNNImanager
=
()
=>
{
const
{
nniManagerLogStr
}
=
this
.
state
;
downFile
(
nniManagerLogStr
,
'
nnimanager.log
'
);
}
downloadDispatcher
=
()
=>
{
const
{
dispatcherLogStr
}
=
this
.
state
;
downFile
(
dispatcherLogStr
,
'
dispatcher.log
'
);
}
dispatcherHTML
=
()
=>
{
return
(
<
div
>
<
span
>
Dispatcher Log
</
span
>
<
span
className
=
"refresh"
onClick
=
{
this
.
getdispatcherLogmessage
}
>
<
Icon
type
=
"sync"
/>
</
span
>
</
div
>
);
}
nnimanagerHTML
=
()
=>
{
return
(
<
div
>
<
span
>
NNImanager Log
</
span
>
<
span
className
=
"refresh"
onClick
=
{
this
.
getNNImanagerLogmessage
}
><
Icon
type
=
"sync"
/></
span
>
</
div
>
);
}
componentDidMount
()
{
this
.
_isLogDrawer
=
true
;
this
.
getNNImanagerLogmessage
();
this
.
getdispatcherLogmessage
();
}
componentWillReceiveProps
(
nextProps
:
LogDrawerProps
)
{
const
{
isVisble
,
activeTab
}
=
nextProps
;
if
(
isVisble
===
true
)
{
if
(
activeTab
===
'
nnimanager
'
)
{
this
.
getNNImanagerLogmessage
();
}
if
(
activeTab
===
'
dispatcher
'
)
{
this
.
getdispatcherLogmessage
();
}
}
}
componentWillUnmount
()
{
this
.
_isLogDrawer
=
false
;
}
render
()
{
const
{
isVisble
,
closeDrawer
,
activeTab
}
=
this
.
props
;
const
{
nniManagerLogStr
,
dispatcherLogStr
,
isLoadispatcher
,
isLoading
}
=
this
.
state
;
const
heights
:
number
=
window
.
innerHeight
-
48
;
// padding top and bottom
return
(
<
Row
>
<
Drawer
placement
=
"right"
closable
=
{
false
}
destroyOnClose
=
{
true
}
onClose
=
{
closeDrawer
}
visible
=
{
isVisble
}
width
=
"76%"
height
=
{
heights
}
// className="logDrawer"
>
<
div
className
=
"card-container log-tab-body"
style
=
{
{
height
:
heights
}
}
>
<
Tabs
type
=
"card"
defaultActiveKey
=
{
activeTab
}
>
{
/* <Tabs type="card" onTabClick={this.selectwhichLog} defaultActiveKey={activeTab}> */
}
{
/* <TabPane tab="Dispatcher Log" key="dispatcher"> */
}
<
TabPane
tab
=
{
this
.
dispatcherHTML
()
}
key
=
"dispatcher"
>
<
div
>
<
MonacoHTML
content
=
{
dispatcherLogStr
}
loading
=
{
isLoadispatcher
}
/>
</
div
>
<
Row
className
=
"buttons"
>
<
Col
span
=
{
12
}
>
<
Button
type
=
"primary"
onClick
=
{
this
.
downloadDispatcher
}
>
Download
</
Button
>
</
Col
>
<
Col
span
=
{
12
}
className
=
"close"
>
<
Button
type
=
"default"
onClick
=
{
closeDrawer
}
>
Close
</
Button
>
</
Col
>
</
Row
>
</
TabPane
>
<
TabPane
tab
=
{
this
.
nnimanagerHTML
()
}
key
=
"nnimanager"
>
{
/* <TabPane tab="NNImanager Log" key="nnimanager"> */
}
<
div
>
<
MonacoHTML
content
=
{
nniManagerLogStr
}
loading
=
{
isLoading
}
/>
</
div
>
<
Row
className
=
"buttons"
>
<
Col
span
=
{
12
}
className
=
"download"
>
<
Button
type
=
"primary"
onClick
=
{
this
.
downloadNNImanager
}
>
Download
</
Button
>
</
Col
>
<
Col
span
=
{
12
}
className
=
"close"
>
<
Button
type
=
"default"
onClick
=
{
closeDrawer
}
>
Close
</
Button
>
</
Col
>
</
Row
>
</
TabPane
>
</
Tabs
>
</
div
>
</
Drawer
>
</
Row
>
);
}
}
export
default
LogDrawer
;
src/webui/src/components/SlideBar.tsx
View file @
4bbffd17
...
...
@@ -3,10 +3,11 @@ import { Link } from 'react-router';
import
axios
from
'
axios
'
;
import
{
MANAGER_IP
}
from
'
../static/const
'
;
import
MediaQuery
from
'
react-responsive
'
;
import
{
DOWNLOAD_IP
}
from
'
../static/const
'
;
import
{
Row
,
Col
,
Menu
,
Dropdown
,
Icon
,
Select
,
Button
}
from
'
antd
'
;
const
{
SubMenu
}
=
Menu
;
const
{
Option
}
=
Select
;
import
LogDrawer
from
'
./Modal/LogDrawer
'
;
import
ExperimentDrawer
from
'
./Modal/ExperimentDrawer
'
;
import
'
../static/style/slideBar.scss
'
;
import
'
../static/style/button.scss
'
;
...
...
@@ -15,6 +16,9 @@ interface SliderState {
menuVisible
:
boolean
;
navBarVisible
:
boolean
;
isdisabledFresh
:
boolean
;
isvisibleLogDrawer
:
boolean
;
isvisibleExperimentDrawer
:
boolean
;
activeKey
:
string
;
}
interface
SliderProps
{
...
...
@@ -38,124 +42,13 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
version
:
''
,
menuVisible
:
false
,
navBarVisible
:
false
,
isdisabledFresh
:
false
isdisabledFresh
:
false
,
isvisibleLogDrawer
:
false
,
// download button (nnimanager·dispatcher) click -> drawer
isvisibleExperimentDrawer
:
false
,
activeKey
:
'
dispatcher
'
};
}
downExperimentContent
=
()
=>
{
axios
.
all
([
axios
.
get
(
`
${
MANAGER_IP
}
/experiment`
),
axios
.
get
(
`
${
MANAGER_IP
}
/trial-jobs`
),
axios
.
get
(
`
${
MANAGER_IP
}
/metric-data`
)
])
.
then
(
axios
.
spread
((
res
,
res1
,
res2
)
=>
{
if
(
res
.
status
===
200
&&
res1
.
status
===
200
&&
res2
.
status
===
200
)
{
if
(
res
.
data
.
params
.
searchSpace
)
{
res
.
data
.
params
.
searchSpace
=
JSON
.
parse
(
res
.
data
.
params
.
searchSpace
);
}
const
isEdge
=
navigator
.
userAgent
.
indexOf
(
'
Edge
'
)
!==
-
1
?
true
:
false
;
let
trialMessagesArr
=
res1
.
data
;
const
interResultList
=
res2
.
data
;
Object
.
keys
(
trialMessagesArr
).
map
(
item
=>
{
// transform hyperparameters as object to show elegantly
trialMessagesArr
[
item
].
hyperParameters
=
JSON
.
parse
(
trialMessagesArr
[
item
].
hyperParameters
);
const
trialId
=
trialMessagesArr
[
item
].
id
;
// add intermediate result message
trialMessagesArr
[
item
].
intermediate
=
[];
Object
.
keys
(
interResultList
).
map
(
key
=>
{
const
interId
=
interResultList
[
key
].
trialJobId
;
if
(
trialId
===
interId
)
{
trialMessagesArr
[
item
].
intermediate
.
push
(
interResultList
[
key
]);
}
});
});
const
result
=
{
experimentParameters
:
res
.
data
,
trialMessage
:
trialMessagesArr
};
const
aTag
=
document
.
createElement
(
'
a
'
);
const
file
=
new
Blob
([
JSON
.
stringify
(
result
,
null
,
4
)],
{
type
:
'
application/json
'
});
aTag
.
download
=
'
experiment.json
'
;
aTag
.
href
=
URL
.
createObjectURL
(
file
);
aTag
.
click
();
if
(
!
isEdge
)
{
URL
.
revokeObjectURL
(
aTag
.
href
);
}
if
(
navigator
.
userAgent
.
indexOf
(
'
Firefox
'
)
>
-
1
)
{
const
downTag
=
document
.
createElement
(
'
a
'
);
downTag
.
addEventListener
(
'
click
'
,
function
()
{
downTag
.
download
=
'
experiment.json
'
;
downTag
.
href
=
URL
.
createObjectURL
(
file
);
});
let
eventMouse
=
document
.
createEvent
(
'
MouseEvents
'
);
eventMouse
.
initEvent
(
'
click
'
,
false
,
false
);
downTag
.
dispatchEvent
(
eventMouse
);
}
}
}));
}
downnnimanagerLog
=
()
=>
{
axios
(
`
${
DOWNLOAD_IP
}
/nnimanager.log`
,
{
method
:
'
GET
'
})
.
then
(
res
=>
{
if
(
res
.
status
===
200
)
{
const
nniLogfile
=
res
.
data
;
const
aTag
=
document
.
createElement
(
'
a
'
);
const
isEdge
=
navigator
.
userAgent
.
indexOf
(
'
Edge
'
)
!==
-
1
?
true
:
false
;
const
file
=
new
Blob
([
nniLogfile
],
{
type
:
'
application/json
'
});
aTag
.
download
=
'
nnimanagerLog.log
'
;
aTag
.
href
=
URL
.
createObjectURL
(
file
);
aTag
.
click
();
if
(
!
isEdge
)
{
URL
.
revokeObjectURL
(
aTag
.
href
);
}
if
(
navigator
.
userAgent
.
indexOf
(
'
Firefox
'
)
>
-
1
)
{
const
downTag
=
document
.
createElement
(
'
a
'
);
downTag
.
addEventListener
(
'
click
'
,
function
()
{
downTag
.
download
=
'
nnimanagerLog.log
'
;
downTag
.
href
=
URL
.
createObjectURL
(
file
);
});
let
eventMouse
=
document
.
createEvent
(
'
MouseEvents
'
);
eventMouse
.
initEvent
(
'
click
'
,
false
,
false
);
downTag
.
dispatchEvent
(
eventMouse
);
}
}
});
}
downDispatcherlog
=
()
=>
{
axios
(
`
${
DOWNLOAD_IP
}
/dispatcher.log`
,
{
method
:
'
GET
'
})
.
then
(
res
=>
{
if
(
res
.
status
===
200
)
{
const
dispatchLogfile
=
res
.
data
;
const
aTag
=
document
.
createElement
(
'
a
'
);
const
isEdge
=
navigator
.
userAgent
.
indexOf
(
'
Edge
'
)
!==
-
1
?
true
:
false
;
const
file
=
new
Blob
([
dispatchLogfile
],
{
type
:
'
application/json
'
});
aTag
.
download
=
'
dispatcherLog.log
'
;
aTag
.
href
=
URL
.
createObjectURL
(
file
);
aTag
.
click
();
if
(
!
isEdge
)
{
URL
.
revokeObjectURL
(
aTag
.
href
);
}
if
(
navigator
.
userAgent
.
indexOf
(
'
Firefox
'
)
>
-
1
)
{
const
downTag
=
document
.
createElement
(
'
a
'
);
downTag
.
addEventListener
(
'
click
'
,
function
()
{
downTag
.
download
=
'
dispatcherLog.log
'
;
downTag
.
href
=
URL
.
createObjectURL
(
file
);
});
let
eventMouse
=
document
.
createEvent
(
'
MouseEvents
'
);
eventMouse
.
initEvent
(
'
click
'
,
false
,
false
);
downTag
.
dispatchEvent
(
eventMouse
);
}
}
});
}
getNNIversion
=
()
=>
{
axios
(
`
${
MANAGER_IP
}
/version`
,
{
method
:
'
GET
'
...
...
@@ -170,17 +63,23 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
handleMenuClick
=
(
e
:
EventPer
)
=>
{
if
(
this
.
_isMounted
)
{
this
.
setState
({
menuVisible
:
false
});
}
switch
(
e
.
key
)
{
// download experiment
related content
//
to see &
download experiment
parameters
case
'
1
'
:
this
.
downExperimentContent
();
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
isvisibleExperimentDrawer
:
true
}));
}
break
;
// download nnimanager log
file
//
to see &
download nnimanager log
case
'
2
'
:
this
.
downnnimanagerLog
();
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
activeKey
:
'
nnimanager
'
,
isvisibleLogDrawer
:
true
}));
}
break
;
// download dispatcher log
file
//
to see &
download dispatcher log
case
'
3
'
:
this
.
downDispatcherlog
();
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
isvisibleLogDrawer
:
true
,
activeKey
:
'
dispatcher
'
}));
}
break
;
case
'
close
'
:
case
'
10
'
:
...
...
@@ -285,6 +184,20 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
}
}
// close log drawer (nnimanager.dispatcher)
closeLogDrawer
=
()
=>
{
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
isvisibleLogDrawer
:
false
,
activeKey
:
''
}));
}
}
// close download experiment parameters drawer
closeExpDrawer
=
()
=>
{
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
isvisibleExperimentDrawer
:
false
}));
}
}
componentDidMount
()
{
this
.
_isMounted
=
true
;
this
.
getNNIversion
();
...
...
@@ -295,9 +208,10 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
}
render
()
{
const
{
version
,
menuVisible
}
=
this
.
state
;
const
{
version
,
menuVisible
,
isvisibleLogDrawer
,
activeKey
,
isvisibleExperimentDrawer
}
=
this
.
state
;
const
feed
=
`https://github.com/Microsoft/nni/issues/new?labels=
${
version
}
`
;
return
(
<
Row
>
<
Row
>
<
Col
span
=
{
18
}
>
<
MediaQuery
query
=
"(min-width: 1299px)"
>
...
...
@@ -369,6 +283,17 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
</
Col
>
<
Col
span
=
{
3
}
>
{
this
.
select
()
}
</
Col
>
</
Row
>
{
/* the drawer for dispatcher & nnimanager log message */
}
<
LogDrawer
isVisble
=
{
isvisibleLogDrawer
}
closeDrawer
=
{
this
.
closeLogDrawer
}
activeTab
=
{
activeKey
}
/>
<
ExperimentDrawer
isVisble
=
{
isvisibleExperimentDrawer
}
closeExpDrawer
=
{
this
.
closeExpDrawer
}
/>
</
Row
>
);
}
}
...
...
src/webui/src/components/overview/Progress.tsx
View file @
4bbffd17
...
...
@@ -7,6 +7,7 @@ import { MANAGER_IP, CONTROLTYPE } from '../../static/const';
import
{
Experiment
,
TrialNumber
}
from
'
../../static/interface
'
;
import
{
convertTime
}
from
'
../../static/function
'
;
import
ProgressBar
from
'
./ProgressItem
'
;
import
LogDrawer
from
'
../Modal/LogDrawer
'
;
import
'
../../static/style/progress.scss
'
;
import
'
../../static/style/probar.scss
'
;
...
...
@@ -24,6 +25,7 @@ interface ProgressState {
isEnable
:
boolean
;
userInputVal
:
string
;
// get user input
cancelSty
:
string
;
isShowLogDrawer
:
boolean
;
}
class
Progressed
extends
React
.
Component
<
ProgressProps
,
ProgressState
>
{
...
...
@@ -36,7 +38,8 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
btnName
:
'
Edit
'
,
isEnable
:
true
,
userInputVal
:
this
.
props
.
trialProfile
.
runConcurren
.
toString
(),
cancelSty
:
'
none
'
cancelSty
:
'
none
'
,
isShowLogDrawer
:
false
};
}
...
...
@@ -139,6 +142,18 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
}
}
isShowDrawer
=
()
=>
{
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
isShowLogDrawer
:
true
}));
}
}
closeDrawer
=
()
=>
{
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
isShowLogDrawer
:
false
}));
}
}
componentWillReceiveProps
()
{
const
{
trialProfile
}
=
this
.
props
;
if
(
this
.
conInput
!==
null
)
{
...
...
@@ -156,7 +171,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
render
()
{
const
{
trialProfile
,
trialNumber
,
bestAccuracy
,
status
,
errors
}
=
this
.
props
;
const
{
isEnable
,
btnName
,
cancelSty
}
=
this
.
state
;
const
{
isEnable
,
btnName
,
cancelSty
,
isShowLogDrawer
}
=
this
.
state
;
const
bar2
=
trialNumber
.
totalCurrentTrial
-
trialNumber
.
waitTrial
-
trialNumber
.
unknowTrial
;
const
bar2Percent
=
(
bar2
/
trialProfile
.
MaxTrialNum
)
*
100
;
const
percent
=
(
trialProfile
.
execDuration
/
trialProfile
.
maxDuration
)
*
100
;
...
...
@@ -173,6 +188,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
errorContent
=
(
<
div
className
=
"errors"
>
{
errors
}
<
div
><
a
href
=
"#"
onClick
=
{
this
.
isShowDrawer
}
>
Learn about
</
a
></
div
>
</
div
>
);
}
...
...
@@ -282,8 +298,13 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
<
div
>
{
trialNumber
.
failTrial
}
</
div
>
</
Row
>
</
Col
>
</
Row
>
{
/* learn about click -> default active key is dispatcher. */
}
<
LogDrawer
isVisble
=
{
isShowLogDrawer
}
closeDrawer
=
{
this
.
closeDrawer
}
activeTab
=
"dispatcher"
/>
</
Row
>
);
}
...
...
src/webui/src/components/public-child/MonacoEditor.tsx
0 → 100644
View file @
4bbffd17
import
*
as
React
from
'
react
'
;
import
{
Spin
}
from
'
antd
'
;
import
{
DRAWEROPTION
}
from
'
../../static/const
'
;
import
MonacoEditor
from
'
react-monaco-editor
'
;
interface
MonacoEditorProps
{
content
:
string
;
loading
:
boolean
;
}
class
MonacoHTML
extends
React
.
Component
<
MonacoEditorProps
,
{}
>
{
public
_isMonacoMount
:
boolean
;
constructor
(
props
:
MonacoEditorProps
)
{
super
(
props
);
}
componentDidMount
()
{
this
.
_isMonacoMount
=
true
;
}
componentWillUnmount
()
{
this
.
_isMonacoMount
=
false
;
}
render
()
{
const
{
content
,
loading
}
=
this
.
props
;
const
heights
:
number
=
window
.
innerHeight
-
48
;
return
(
<
div
className
=
"just-for-log"
>
<
Spin
// tip="Loading..."
style
=
{
{
width
:
'
100%
'
,
height
:
heights
*
0.9
}
}
spinning
=
{
loading
}
>
<
MonacoEditor
width
=
"100%"
height
=
{
heights
*
0.9
}
language
=
"json"
value
=
{
content
}
options
=
{
DRAWEROPTION
}
/>
</
Spin
>
</
div
>
);
}
}
export
default
MonacoHTML
;
src/webui/src/static/const.ts
View file @
4bbffd17
...
...
@@ -19,6 +19,11 @@ const MONACO = {
readOnly
:
true
,
automaticLayout
:
true
};
const
DRAWEROPTION
=
{
minimap
:
{
enabled
:
false
},
readOnly
:
true
,
automaticLayout
:
true
};
const
COLUMN_INDEX
=
[
{
name
:
'
Trial No.
'
,
...
...
@@ -52,5 +57,5 @@ const COLUMN_INDEX = [
const
COLUMN
=
[
'
Trial No.
'
,
'
ID
'
,
'
Duration
'
,
'
Status
'
,
'
Default
'
,
'
Operation
'
,
'
Intermediate result
'
];
export
{
MANAGER_IP
,
DOWNLOAD_IP
,
trialJobStatus
,
CONTROLTYPE
,
MONACO
,
COLUMN
,
COLUMN_INDEX
CONTROLTYPE
,
MONACO
,
COLUMN
,
COLUMN_INDEX
,
DRAWEROPTION
};
src/webui/src/static/function.ts
View file @
4bbffd17
...
...
@@ -138,7 +138,29 @@ const filterDuration = (item: TableObj) => {
return
item
.
status
!==
'
WAITING
'
;
};
const
downFile
=
(
content
:
string
,
fileName
:
string
)
=>
{
const
aTag
=
document
.
createElement
(
'
a
'
);
const
isEdge
=
navigator
.
userAgent
.
indexOf
(
'
Edge
'
)
!==
-
1
?
true
:
false
;
const
file
=
new
Blob
([
content
],
{
type
:
'
application/json
'
});
aTag
.
download
=
fileName
;
aTag
.
href
=
URL
.
createObjectURL
(
file
);
aTag
.
click
();
if
(
!
isEdge
)
{
URL
.
revokeObjectURL
(
aTag
.
href
);
}
if
(
navigator
.
userAgent
.
indexOf
(
'
Firefox
'
)
>
-
1
)
{
const
downTag
=
document
.
createElement
(
'
a
'
);
downTag
.
addEventListener
(
'
click
'
,
function
()
{
downTag
.
download
=
fileName
;
downTag
.
href
=
URL
.
createObjectURL
(
file
);
});
let
eventMouse
=
document
.
createEvent
(
'
MouseEvents
'
);
eventMouse
.
initEvent
(
'
click
'
,
false
,
false
);
downTag
.
dispatchEvent
(
eventMouse
);
}
};
export
{
convertTime
,
convertDuration
,
getFinalResult
,
getFinal
,
convertTime
,
convertDuration
,
getFinalResult
,
getFinal
,
downFile
,
intermediateGraphOption
,
killJob
,
filterByStatus
,
filterDuration
};
src/webui/src/static/style/button.scss
View file @
4bbffd17
$btnBgcolor
:
#0071bc
;
Button
.tableButton
{
font-family
:
'Segoe UI'
,
Tahoma
,
Geneva
,
Verdana
,
sans-serif
;
background
:
$btnBgcolor
;
border-color
:
$btnBgcolor
;
height
:
26px
;
...
...
src/webui/src/static/style/compare.scss
View file @
4bbffd17
...
...
@@ -12,7 +12,7 @@
.column
{
max-width
:
124px
;
padding-left
:
18px
;
font-weight
:
7
00
;
font-weight
:
6
00
;
}
.value
{
max-width
:
152px
;
...
...
@@ -20,6 +20,6 @@
text-align
:
left
;
}
.idList
{
font-weight
:
7
00
;
font-weight
:
6
00
;
}
}
src/webui/src/static/style/control.scss
View file @
4bbffd17
...
...
@@ -55,7 +55,7 @@ div.addtitle{
font-size
:
20px
;
}
.line
{
font-weight
:
bold
;
font-weight
:
600
;
color
:
rgb
(
60
,
141
,
188
);
padding-right
:
20px
;
}
...
...
src/webui/src/static/style/logDrawer.scss
0 → 100644
View file @
4bbffd17
.card-container
>
.ant-tabs-card
>
.ant-tabs-content
{
margin-top
:
-16px
;
}
.card-container
>
.ant-tabs-card
>
.ant-tabs-content
>
.ant-tabs-tabpane
{
background
:
#fff
;
padding
:
16px
;
}
.card-container
>
.ant-tabs-card
>
.ant-tabs-bar
{
border-color
:
#fff
;
}
.card-container
>
.ant-tabs-card
>
.ant-tabs-bar
.ant-tabs-tab
{
border-color
:
transparent
;
background
:
transparent
;
}
.card-container
>
.ant-tabs-card
>
.ant-tabs-bar
.ant-tabs-tab-active
{
border-color
:
#fff
;
background
:
#fff
;
}
.logContainer
{
height
:
100%
;
}
.buttons
{
margin-top
:
15px
;
.close
{
text-align
:
right
;
}
}
/*
.logDrawer{
width: 100%;
.ant-drawer-body{
box-sizing: border-box;
-webkit-box-sizing: border-box;
}
}
*/
.ant-drawer-body
{
background
:
#333
;
}
.card-container
>
.ant-tabs-card
>
.ant-tabs-bar
{
border
:
none
;
}
.card-container
>
.ant-tabs-card
>
.ant-tabs-content
>
.ant-tabs-tabpane
{
background-color
:
#333
;
}
.close
{
Button
,
Button
:active
,
Button
:hover
{
background-color
:
#212121
;
color
:
#fff
;
border
:
none
;
}
}
.download
{
Button
,
Button
:active
,
Button
:hover
{
background-color
:
#2772be
;
color
:
#fff
;
border
:
none
;
}
}
.log-tab-body
>
.ant-tabs-card
>
.ant-tabs-bar
.ant-tabs-tab-active
{
background-color
:
#1e1e1e
;
color
:
#fff
;
border
:
none
;
}
.log-tab-body
.ant-tabs-nav
.ant-tabs-tab
:hover
,
.log-tab-body
.ant-tabs-nav
.ant-tabs-tab
{
color
:
#fff
;
border
:
none
;
}
.ant-tabs.ant-tabs-card
>
.ant-tabs-bar
.ant-tabs-tab
{
border
:
none
;
}
.log-tab-body
{
.refresh
{
margin-left
:
10px
;
display
:
none
;
}
.ant-tabs-tab-active
{
.refresh
{
transition
:
0
.3s
;
display
:
inline-block
;
}
.refresh
:hover
{
transform
:
scale
(
1
.2
);
}
}
}
.just-for-log
{
.monaco-editor
{
.line-numbers
{
color
:
#fff
;
}
.current-line
~
.line-numbers
{
color
:
#FFFAF0
;
}
}
.view-lines
{
background-color
:
#1e1e1e
;
.mtk1
{
color
:
#fff
;
}
}
.margin-view-overlays
{
background-color
:
#1e1e1e
;
}
}
Prev
1
2
3
4
5
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment