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
9ce751de
Unverified
Commit
9ce751de
authored
Nov 21, 2019
by
SparkSnail
Committed by
GitHub
Nov 21, 2019
Browse files
Merge pull request #216 from microsoft/master
merge master
parents
d16dbe9a
cb52d441
Changes
24
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
440 additions
and
14 deletions
+440
-14
src/sdk/pynni/tests/test_msg_dispatcher.py
src/sdk/pynni/tests/test_msg_dispatcher.py
+1
-10
src/webui/src/components/Modal/CustomizedTrial.tsx
src/webui/src/components/Modal/CustomizedTrial.tsx
+317
-0
src/webui/src/components/Modal/customized.scss
src/webui/src/components/Modal/customized.scss
+71
-0
src/webui/src/components/trial-detail/TableList.tsx
src/webui/src/components/trial-detail/TableList.tsx
+51
-4
No files found.
src/sdk/pynni/tests/test_msg_dispatcher.py
View file @
9ce751de
...
@@ -80,8 +80,6 @@ class MsgDispatcherTestCase(TestCase):
...
@@ -80,8 +80,6 @@ class MsgDispatcherTestCase(TestCase):
send
(
CommandType
.
ReportMetricData
,
'{"parameter_id":0,"type":"PERIODICAL","value":10}'
)
send
(
CommandType
.
ReportMetricData
,
'{"parameter_id":0,"type":"PERIODICAL","value":10}'
)
send
(
CommandType
.
ReportMetricData
,
'{"parameter_id":1,"type":"FINAL","value":11}'
)
send
(
CommandType
.
ReportMetricData
,
'{"parameter_id":1,"type":"FINAL","value":11}'
)
send
(
CommandType
.
UpdateSearchSpace
,
'{"name":"SS0"}'
)
send
(
CommandType
.
UpdateSearchSpace
,
'{"name":"SS0"}'
)
send
(
CommandType
.
AddCustomizedTrialJob
,
'{"param":-1}'
)
send
(
CommandType
.
ReportMetricData
,
'{"parameter_id":2,"type":"FINAL","value":22}'
)
send
(
CommandType
.
RequestTrialJobs
,
'1'
)
send
(
CommandType
.
RequestTrialJobs
,
'1'
)
send
(
CommandType
.
KillTrialJob
,
'null'
)
send
(
CommandType
.
KillTrialJob
,
'null'
)
_restore_io
()
_restore_io
()
...
@@ -99,14 +97,7 @@ class MsgDispatcherTestCase(TestCase):
...
@@ -99,14 +97,7 @@ class MsgDispatcherTestCase(TestCase):
self
.
_assert_params
(
0
,
2
,
[],
None
)
self
.
_assert_params
(
0
,
2
,
[],
None
)
self
.
_assert_params
(
1
,
4
,
[],
None
)
self
.
_assert_params
(
1
,
4
,
[],
None
)
command
,
data
=
receive
()
# this one is customized
self
.
_assert_params
(
2
,
6
,
[[
1
,
4
,
11
,
False
]],
{
'name'
:
'SS0'
})
data
=
json
.
loads
(
data
)
self
.
assertIs
(
command
,
CommandType
.
NewTrialJob
)
self
.
assertEqual
(
data
[
'parameter_id'
],
2
)
self
.
assertEqual
(
data
[
'parameter_source'
],
'customized'
)
self
.
assertEqual
(
data
[
'parameters'
],
{
'param'
:
-
1
})
self
.
_assert_params
(
3
,
6
,
[[
1
,
4
,
11
,
False
],
[
2
,
-
1
,
22
,
True
]],
{
'name'
:
'SS0'
})
self
.
assertEqual
(
len
(
_out_buf
.
read
()),
0
)
# no more commands
self
.
assertEqual
(
len
(
_out_buf
.
read
()),
0
)
# no more commands
...
...
src/webui/src/components/Modal/CustomizedTrial.tsx
0 → 100644
View file @
9ce751de
import
*
as
React
from
'
react
'
;
import
axios
from
'
axios
'
;
import
{
Row
,
Col
,
Input
,
Modal
,
Form
,
Button
,
Icon
}
from
'
antd
'
;
import
{
MANAGER_IP
}
from
'
../../static/const
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
FormComponentProps
}
from
'
antd/lib/form
'
;
const
FormItem
=
Form
.
Item
;
import
'
./customized.scss
'
;
interface
CustomizeProps
extends
FormComponentProps
{
visible
:
boolean
;
copyTrialId
:
string
;
closeCustomizeModal
:
()
=>
void
;
}
interface
CustomizeState
{
isShowSubmitSucceed
:
boolean
;
isShowSubmitFailed
:
boolean
;
isShowWarning
:
boolean
;
searchSpace
:
object
;
copyTrialParameter
:
object
;
// user click the trial's parameters
customParameters
:
object
;
// customized trial, maybe user change trial's parameters
customID
:
number
;
// submit customized trial succeed, return the new customized trial id
}
class
Customize
extends
React
.
Component
<
CustomizeProps
,
CustomizeState
>
{
constructor
(
props
:
CustomizeProps
)
{
super
(
props
);
this
.
state
=
{
isShowSubmitSucceed
:
false
,
isShowSubmitFailed
:
false
,
isShowWarning
:
false
,
searchSpace
:
EXPERIMENT
.
searchSpace
,
copyTrialParameter
:
{},
customParameters
:
{},
customID
:
NaN
};
}
// [submit click] user add a new trial [submit a trial]
addNewTrial
=
()
=>
{
const
{
searchSpace
,
copyTrialParameter
}
=
this
.
state
;
// get user edited hyperParameter, ps: will change data type if you modify the input val
const
customized
=
this
.
props
.
form
.
getFieldsValue
();
// true: parameters are wrong
let
flag
=
false
;
Object
.
keys
(
customized
).
map
(
item
=>
{
if
(
item
!==
'
tag
'
)
{
// unified data type
if
(
typeof
copyTrialParameter
[
item
]
===
'
number
'
&&
typeof
customized
[
item
]
===
'
string
'
)
{
customized
[
item
]
=
JSON
.
parse
(
customized
[
item
]);
}
if
(
searchSpace
[
item
].
_type
===
'
choice
'
)
{
if
(
searchSpace
[
item
].
_value
.
find
((
val
:
string
|
number
)
=>
val
===
customized
[
item
])
===
undefined
)
{
flag
=
true
;
return
;
}
}
else
{
if
(
customized
[
item
]
<
searchSpace
[
item
].
_value
[
0
]
||
customized
[
item
]
>
searchSpace
[
item
].
_value
[
1
])
{
flag
=
true
;
return
;
}
}
}
});
if
(
flag
!==
false
)
{
// open the warning modal
this
.
setState
(()
=>
({
isShowWarning
:
true
,
customParameters
:
customized
}));
}
else
{
// submit a customized job
this
.
submitCustomize
(
customized
);
}
}
warningConfirm
=
()
=>
{
this
.
setState
(()
=>
({
isShowWarning
:
false
}));
const
{
customParameters
}
=
this
.
state
;
this
.
submitCustomize
(
customParameters
);
}
warningCancel
=
()
=>
{
this
.
setState
(()
=>
({
isShowWarning
:
false
}));
}
submitCustomize
=
(
customized
:
Object
)
=>
{
// delete `tag` key
for
(
let
i
in
customized
)
{
if
(
i
===
'
tag
'
)
{
delete
customized
[
i
];
}
}
axios
(
`
${
MANAGER_IP
}
/trial-jobs`
,
{
method
:
'
POST
'
,
headers
:
{
'
Content-Type
'
:
'
application/json
'
},
data
:
customized
})
.
then
(
res
=>
{
if
(
res
.
status
===
200
)
{
this
.
setState
(()
=>
({
isShowSubmitSucceed
:
true
,
customID
:
res
.
data
.
sequenceId
}));
this
.
props
.
closeCustomizeModal
();
}
else
{
this
.
setState
(()
=>
({
isShowSubmitFailed
:
true
}));
}
})
.
catch
(
error
=>
{
this
.
setState
(()
=>
({
isShowSubmitFailed
:
true
}));
});
}
closeSucceedHint
=
()
=>
{
// also close customized trial modal
this
.
setState
(()
=>
({
isShowSubmitSucceed
:
false
}));
this
.
props
.
closeCustomizeModal
();
}
closeFailedHint
=
()
=>
{
// also close customized trial modal
this
.
setState
(()
=>
({
isShowSubmitFailed
:
false
}));
this
.
props
.
closeCustomizeModal
();
}
componentDidMount
()
{
const
{
copyTrialId
}
=
this
.
props
;
if
(
copyTrialId
!==
undefined
&&
TRIALS
.
getTrial
(
copyTrialId
)
!==
undefined
)
{
const
originCopyTrialPara
=
TRIALS
.
getTrial
(
copyTrialId
).
description
.
parameters
;
this
.
setState
(()
=>
({
copyTrialParameter
:
originCopyTrialPara
}));
}
}
componentWillReceiveProps
(
nextProps
:
CustomizeProps
)
{
const
{
copyTrialId
}
=
nextProps
;
if
(
copyTrialId
!==
undefined
&&
TRIALS
.
getTrial
(
copyTrialId
)
!==
undefined
)
{
const
originCopyTrialPara
=
TRIALS
.
getTrial
(
copyTrialId
).
description
.
parameters
;
this
.
setState
(()
=>
({
copyTrialParameter
:
originCopyTrialPara
}));
}
}
render
()
{
const
{
closeCustomizeModal
,
visible
}
=
this
.
props
;
const
{
isShowSubmitSucceed
,
isShowSubmitFailed
,
isShowWarning
,
customID
,
copyTrialParameter
}
=
this
.
state
;
const
{
form
:
{
getFieldDecorator
},
// form: { getFieldDecorator, getFieldValue },
}
=
this
.
props
;
const
warning
=
'
The parameters you set are not in our search space, this may cause the tuner to crash, Are
'
+
'
you sure you want to continue submitting?
'
;
return
(
<
Row
>
{
/* form: search space */
}
<
Modal
title
=
"Customized trial setting"
visible
=
{
visible
}
onCancel
=
{
closeCustomizeModal
}
footer
=
{
null
}
destroyOnClose
=
{
true
}
maskClosable
=
{
false
}
centered
=
{
true
}
>
{
/* search space form */
}
<
Row
className
=
"hyper-box"
>
<
Form
>
{
Object
.
keys
(
copyTrialParameter
).
map
(
item
=>
(
<
Row
key
=
{
item
}
className
=
"hyper-form"
>
<
Col
span
=
{
9
}
className
=
"title"
>
{
item
}
</
Col
>
<
Col
span
=
{
15
}
className
=
"inputs"
>
<
FormItem
key
=
{
item
}
style
=
{
{
marginBottom
:
0
}
}
>
{
getFieldDecorator
(
item
,
{
initialValue
:
copyTrialParameter
[
item
],
})(
<
Input
/>
)
}
</
FormItem
>
</
Col
>
</
Row
>
)
)
}
<
Row
key
=
"tag"
className
=
"hyper-form tag-input"
>
<
Col
span
=
{
9
}
className
=
"title"
>
Tag
</
Col
>
<
Col
span
=
{
15
}
className
=
"inputs"
>
<
FormItem
key
=
"tag"
style
=
{
{
marginBottom
:
0
}
}
>
{
getFieldDecorator
(
'
tag
'
,
{
initialValue
:
'
Customized
'
,
})(
<
Input
/>
)
}
</
FormItem
>
</
Col
>
</
Row
>
</
Form
>
</
Row
>
<
Row
className
=
"modal-button"
>
<
Button
type
=
"primary"
className
=
"tableButton distance"
onClick
=
{
this
.
addNewTrial
}
>
Submit
</
Button
>
<
Button
className
=
"tableButton cancelSty"
onClick
=
{
this
.
props
.
closeCustomizeModal
}
>
Cancel
</
Button
>
</
Row
>
{
/* control button */
}
</
Modal
>
{
/* clone: prompt succeed or failed */
}
<
Modal
visible
=
{
isShowSubmitSucceed
}
footer
=
{
null
}
destroyOnClose
=
{
true
}
maskClosable
=
{
false
}
closable
=
{
false
}
centered
=
{
true
}
>
<
Row
className
=
"resubmit"
>
<
Row
>
<
h2
className
=
"title"
>
<
span
>
<
Icon
type
=
"check-circle"
className
=
"color-succ"
/>
<
b
>
Submit successfully
</
b
>
</
span
>
</
h2
>
<
div
className
=
"hint"
>
<
span
>
You can find your customized trial by Trial No.
{
customID
}
</
span
>
</
div
>
</
Row
>
<
Row
className
=
"modal-button"
>
<
Button
className
=
"tableButton cancelSty"
onClick
=
{
this
.
closeSucceedHint
}
>
OK
</
Button
>
</
Row
>
</
Row
>
</
Modal
>
<
Modal
visible
=
{
isShowSubmitFailed
}
footer
=
{
null
}
destroyOnClose
=
{
true
}
maskClosable
=
{
false
}
closable
=
{
false
}
centered
=
{
true
}
>
<
Row
className
=
"resubmit"
>
<
Row
>
<
h2
className
=
"title"
>
<
span
>
<
Icon
type
=
"check-circle"
className
=
"color-error"
/>
Submit Failed
</
span
>
</
h2
>
<
div
className
=
"hint"
>
<
span
>
Unknown error.
</
span
>
</
div
>
</
Row
>
<
Row
className
=
"modal-button"
>
<
Button
className
=
"tableButton cancelSty"
onClick
=
{
this
.
closeFailedHint
}
>
OK
</
Button
>
</
Row
>
</
Row
>
</
Modal
>
{
/* hyperParameter not match search space, warning modal */
}
<
Modal
visible
=
{
isShowWarning
}
footer
=
{
null
}
destroyOnClose
=
{
true
}
maskClosable
=
{
false
}
closable
=
{
false
}
centered
=
{
true
}
>
<
Row
className
=
"resubmit"
>
<
Row
>
<
h2
className
=
"title"
>
<
span
>
<
Icon
className
=
"color-warn"
type
=
"warning"
/>
Warning
</
span
>
</
h2
>
<
div
className
=
"hint"
>
<
span
>
{
warning
}
</
span
>
</
div
>
</
Row
>
<
Row
className
=
"modal-button center"
>
<
Button
className
=
"tableButton cancelSty distance"
onClick
=
{
this
.
warningConfirm
}
>
Confirm
</
Button
>
<
Button
className
=
"tableButton cancelSty"
onClick
=
{
this
.
warningCancel
}
>
Cancel
</
Button
>
</
Row
>
</
Row
>
</
Modal
>
</
Row
>
);
}
}
export
default
Form
.
create
<
FormComponentProps
>
()(
Customize
);
\ No newline at end of file
src/webui/src/components/Modal/customized.scss
0 → 100644
View file @
9ce751de
.ant-modal-body
{
border-radius
:
none
;
}
.ant-modal-title
{
font-size
:
18px
;
}
/* resubmit confirm modal style */
.resubmit
{
.title
{
font-size
:
16px
;
color
:
#000
;
.color-warn
,
.color-error
{
color
:
red
;
}
i
{
margin-right
:
10px
;
}
}
.hint
{
padding
:
15px
0
;
color
:
#333
;
margin-left
:
30px
;
}
.color-succ
{
color
:
green
;
}
}
.hyper-box
{
padding
:
16px
18px
16px
16px
;
}
.hyper-form
{
height
:
32px
;
margin-bottom
:
8px
;
.title
{
font-size
:
14px
;
font-family
:
'Segoe UI'
,
Tahoma
,
Geneva
,
Verdana
,
sans-serif
;
line-height
:
32px
;
}
.inputs
{
height
:
32px
;
}
input
{
height
:
32px
;
}
}
.tag-input
{
margin-top
:
25px
;
}
/* submit & cancel buttons style*/
.modal-button
{
text-align
:
right
;
height
:
28px
;
/* cancel button style*/
.cancelSty
{
width
:
80px
;
background-color
:
#dadada
;
border
:
none
;
color
:
#333
;
}
.cancelSty
:hover
,
.cancelSty
:active
,
.cancelSty
:focus
{
background-color
:
#dadada
;
}
.distance
{
margin-right
:
8px
;
}
}
.center
{
text-align
:
center
;
}
src/webui/src/components/trial-detail/TableList.tsx
View file @
9ce751de
...
@@ -7,10 +7,11 @@ const Option = Select.Option;
...
@@ -7,10 +7,11 @@ const Option = Select.Option;
const
CheckboxGroup
=
Checkbox
.
Group
;
const
CheckboxGroup
=
Checkbox
.
Group
;
import
{
MANAGER_IP
,
trialJobStatus
,
COLUMN_INDEX
,
COLUMNPro
}
from
'
../../static/const
'
;
import
{
MANAGER_IP
,
trialJobStatus
,
COLUMN_INDEX
,
COLUMNPro
}
from
'
../../static/const
'
;
import
{
convertDuration
,
formatTimestamp
,
intermediateGraphOption
,
killJob
}
from
'
../../static/function
'
;
import
{
convertDuration
,
formatTimestamp
,
intermediateGraphOption
,
killJob
}
from
'
../../static/function
'
;
import
{
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
TableRecord
}
from
'
../../static/interface
'
;
import
{
TableRecord
}
from
'
../../static/interface
'
;
import
OpenRow
from
'
../public-child/OpenRow
'
;
import
OpenRow
from
'
../public-child/OpenRow
'
;
import
Compare
from
'
../Modal/Compare
'
;
import
Compare
from
'
../Modal/Compare
'
;
import
Customize
from
'
../Modal/CustomizedTrial
'
;
import
'
../../static/style/search.scss
'
;
import
'
../../static/style/search.scss
'
;
require
(
'
../../static/style/tableStatus.css
'
);
require
(
'
../../static/style/tableStatus.css
'
);
require
(
'
../../static/style/logPath.scss
'
);
require
(
'
../../static/style/logPath.scss
'
);
...
@@ -45,6 +46,8 @@ interface TableListState {
...
@@ -45,6 +46,8 @@ interface TableListState {
intermediateData
:
Array
<
object
>
;
// a trial's intermediate results (include dict)
intermediateData
:
Array
<
object
>
;
// a trial's intermediate results (include dict)
intermediateId
:
string
;
intermediateId
:
string
;
intermediateOtherKeys
:
Array
<
string
>
;
intermediateOtherKeys
:
Array
<
string
>
;
isShowCustomizedModal
:
boolean
;
copyTrialId
:
string
;
// user copy trial to submit a new customized trial
}
}
interface
ColumnIndex
{
interface
ColumnIndex
{
...
@@ -71,7 +74,9 @@ class TableList extends React.Component<TableListProps, TableListState> {
...
@@ -71,7 +74,9 @@ class TableList extends React.Component<TableListProps, TableListState> {
selectedRowKeys
:
[],
// close selected trial message after modal closed
selectedRowKeys
:
[],
// close selected trial message after modal closed
intermediateData
:
[],
intermediateData
:
[],
intermediateId
:
''
,
intermediateId
:
''
,
intermediateOtherKeys
:
[]
intermediateOtherKeys
:
[],
isShowCustomizedModal
:
false
,
copyTrialId
:
''
};
};
}
}
...
@@ -236,17 +241,36 @@ class TableList extends React.Component<TableListProps, TableListState> {
...
@@ -236,17 +241,36 @@ class TableList extends React.Component<TableListProps, TableListState> {
this
.
setState
({
isShowCompareModal
:
false
,
selectedRowKeys
:
[],
selectRows
:
[]
});
this
.
setState
({
isShowCompareModal
:
false
,
selectedRowKeys
:
[],
selectRows
:
[]
});
}
}
// open customized trial modal
setCustomizedTrial
=
(
trialId
:
string
)
=>
{
this
.
setState
({
isShowCustomizedModal
:
true
,
copyTrialId
:
trialId
});
}
closeCustomizedTrial
=
()
=>
{
this
.
setState
({
isShowCustomizedModal
:
false
,
copyTrialId
:
''
});
}
render
()
{
render
()
{
const
{
pageSize
,
columnList
}
=
this
.
props
;
const
{
pageSize
,
columnList
}
=
this
.
props
;
const
tableSource
:
Array
<
TableRecord
>
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
props
.
tableSource
));
const
tableSource
:
Array
<
TableRecord
>
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
props
.
tableSource
));
const
{
intermediateOption
,
modalVisible
,
isShowColumn
,
const
{
intermediateOption
,
modalVisible
,
isShowColumn
,
selectRows
,
isShowCompareModal
,
selectedRowKeys
,
intermediateOtherKeys
}
=
this
.
state
;
selectRows
,
isShowCompareModal
,
selectedRowKeys
,
intermediateOtherKeys
,
isShowCustomizedModal
,
copyTrialId
}
=
this
.
state
;
const
rowSelection
=
{
const
rowSelection
=
{
selectedRowKeys
:
selectedRowKeys
,
selectedRowKeys
:
selectedRowKeys
,
onChange
:
(
selected
:
string
[]
|
number
[],
selectedRows
:
Array
<
TableRecord
>
)
=>
{
onChange
:
(
selected
:
string
[]
|
number
[],
selectedRows
:
Array
<
TableRecord
>
)
=>
{
this
.
fillSelectedRowsTostate
(
selected
,
selectedRows
);
this
.
fillSelectedRowsTostate
(
selected
,
selectedRows
);
}
}
};
};
// [supportCustomizedTrial: true]
const
supportCustomizedTrial
=
(
EXPERIMENT
.
multiPhase
===
true
)
?
false
:
true
;
const
disabledAddCustomizedTrial
=
[
'
DONE
'
,
'
ERROR
'
,
'
STOPPED
'
].
includes
(
EXPERIMENT
.
status
);
let
showTitle
=
COLUMNPro
;
let
showTitle
=
COLUMNPro
;
const
showColumn
:
Array
<
object
>
=
[];
const
showColumn
:
Array
<
object
>
=
[];
...
@@ -361,6 +385,22 @@ class TableList extends React.Component<TableListProps, TableListState> {
...
@@ -361,6 +385,22 @@ class TableList extends React.Component<TableListProps, TableListState> {
</
Button
>
</
Button
>
</
Popconfirm
>
</
Popconfirm
>
}
}
{
/* Add a new trial-customized trial */
}
{
supportCustomizedTrial
?
<
Button
type
=
"primary"
className
=
"common-style"
disabled
=
{
disabledAddCustomizedTrial
}
onClick
=
{
this
.
setCustomizedTrial
.
bind
(
this
,
record
.
id
)
}
title
=
"Customized trial"
>
<
Icon
type
=
"copy"
/>
</
Button
>
:
null
}
</
Row
>
</
Row
>
);
);
},
},
...
@@ -398,7 +438,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
...
@@ -398,7 +438,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
expandedRowRender
=
{
this
.
openRow
}
expandedRowRender
=
{
this
.
openRow
}
dataSource
=
{
tableSource
}
dataSource
=
{
tableSource
}
className
=
"commonTableStyle"
className
=
"commonTableStyle"
scroll
=
{
{
x
:
'
max-content
'
}
}
scroll
=
{
{
x
:
'
max-content
'
}
}
pagination
=
{
pageSize
>
0
?
{
pageSize
}
:
false
}
pagination
=
{
pageSize
>
0
?
{
pageSize
}
:
false
}
/>
/>
{
/* Intermediate Result Modal */
}
{
/* Intermediate Result Modal */
}
...
@@ -458,7 +498,14 @@ class TableList extends React.Component<TableListProps, TableListState> {
...
@@ -458,7 +498,14 @@ class TableList extends React.Component<TableListProps, TableListState> {
className
=
"titleColumn"
className
=
"titleColumn"
/>
/>
</
Modal
>
</
Modal
>
{
/* compare trials based message */
}
<
Compare
compareRows
=
{
selectRows
}
visible
=
{
isShowCompareModal
}
cancelFunc
=
{
this
.
hideCompareModal
}
/>
<
Compare
compareRows
=
{
selectRows
}
visible
=
{
isShowCompareModal
}
cancelFunc
=
{
this
.
hideCompareModal
}
/>
{
/* clone trial parameters and could submit a customized trial */
}
<
Customize
visible
=
{
isShowCustomizedModal
}
copyTrialId
=
{
copyTrialId
}
closeCustomizeModal
=
{
this
.
closeCustomizedTrial
}
/>
</
Row
>
</
Row
>
);
);
}
}
...
...
Prev
1
2
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