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
f6343344
Unverified
Commit
f6343344
authored
Jun 21, 2019
by
SparkSnail
Committed by
GitHub
Jun 21, 2019
Browse files
Merge pull request #185 from microsoft/master
merge master
parents
d48ad027
61fec446
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
615 additions
and
285 deletions
+615
-285
src/nni_manager/common/utils.ts
src/nni_manager/common/utils.ts
+35
-1
src/nni_manager/training_service/common/util.ts
src/nni_manager/training_service/common/util.ts
+13
-2
src/webui/package.json
src/webui/package.json
+5
-3
src/webui/src/App.css
src/webui/src/App.css
+1
-5
src/webui/src/App.tsx
src/webui/src/App.tsx
+43
-4
src/webui/src/components/Overview.tsx
src/webui/src/components/Overview.tsx
+50
-27
src/webui/src/components/SlideBar.tsx
src/webui/src/components/SlideBar.tsx
+351
-220
src/webui/src/components/TrialsDetail.tsx
src/webui/src/components/TrialsDetail.tsx
+36
-18
src/webui/src/static/style/slideBar.scss
src/webui/src/static/style/slideBar.scss
+81
-5
No files found.
src/nni_manager/common/utils.ts
View file @
f6343344
...
...
@@ -374,6 +374,40 @@ function countFilesRecursively(directory: string, timeoutMilliSeconds?: number):
});
}
function
validateFileName
(
fileName
:
string
):
boolean
{
let
pattern
:
string
=
'
^[a-z0-9A-Z
\
.-_]+$
'
;
const
validateResult
=
fileName
.
match
(
pattern
);
if
(
validateResult
)
{
return
true
;
}
return
false
;
}
async
function
validateFileNameRecursively
(
directory
:
string
):
Promise
<
boolean
>
{
if
(
!
fs
.
existsSync
(
directory
))
{
throw
Error
(
`Direcotory
${
directory
}
doesn't exist`
);
}
const
fileNameArray
:
string
[]
=
fs
.
readdirSync
(
directory
);
let
result
=
true
;
for
(
var
name
of
fileNameArray
){
const
fullFilePath
:
string
=
path
.
join
(
directory
,
name
);
try
{
// validate file names and directory names
result
=
validateFileName
(
name
);
if
(
fs
.
lstatSync
(
fullFilePath
).
isDirectory
())
{
result
=
result
&&
await
validateFileNameRecursively
(
fullFilePath
);
}
if
(
!
result
)
{
return
Promise
.
reject
(
new
Error
(
`file name in
${
fullFilePath
}
is not valid!`
));
}
}
catch
(
error
)
{
return
Promise
.
reject
(
error
);
}
}
return
Promise
.
resolve
(
result
);
}
/**
* get the version of current package
*/
...
...
@@ -474,6 +508,6 @@ function unixPathJoin(...paths: any[]): string {
return
dir
;
}
export
{
countFilesRecursively
,
getRemoteTmpDir
,
generateParamFileName
,
getMsgDispatcherCommand
,
getCheckpointDir
,
export
{
countFilesRecursively
,
validateFileNameRecursively
,
getRemoteTmpDir
,
generateParamFileName
,
getMsgDispatcherCommand
,
getCheckpointDir
,
getLogDir
,
getExperimentRootDir
,
getJobCancelStatus
,
getDefaultDatabaseDir
,
getIPV4Address
,
unixPathJoin
,
mkDirP
,
delay
,
prepareUnitTest
,
parseArg
,
cleanupUnitTest
,
uniqueString
,
randomSelect
,
getLogLevel
,
getVersion
,
getCmdPy
,
getTunerProc
,
isAlive
,
killPid
,
getNewLine
};
src/nni_manager/training_service/common/util.ts
View file @
f6343344
...
...
@@ -25,7 +25,7 @@ import * as fs from 'fs';
import
*
as
os
from
'
os
'
;
import
*
as
path
from
'
path
'
;
import
{
String
}
from
'
typescript-string-operations
'
;
import
{
countFilesRecursively
,
getNewLine
}
from
'
../../common/utils
'
;
import
{
countFilesRecursively
,
getNewLine
,
validateFileNameRecursively
}
from
'
../../common/utils
'
;
import
{
file
}
from
'
../../node_modules/@types/tmp
'
;
import
{
GPU_INFO_COLLECTOR_FORMAT_LINUX
,
GPU_INFO_COLLECTOR_FORMAT_WINDOWS
}
from
'
./gpuData
'
;
...
...
@@ -38,22 +38,33 @@ import { GPU_INFO_COLLECTOR_FORMAT_LINUX, GPU_INFO_COLLECTOR_FORMAT_WINDOWS } fr
// tslint:disable: no-redundant-jsdoc
export
async
function
validateCodeDir
(
codeDir
:
string
)
:
Promise
<
number
>
{
let
fileCount
:
number
|
undefined
;
let
fileNameValid
:
boolean
=
true
;
try
{
fileCount
=
await
countFilesRecursively
(
codeDir
);
}
catch
(
error
)
{
throw
new
Error
(
`Call count file error:
${
error
}
`
);
}
try
{
fileNameValid
=
await
validateFileNameRecursively
(
codeDir
);
}
catch
(
error
)
{
throw
new
Error
(
`Validate file name error:
${
error
}
`
);
}
if
(
fileCount
!==
undefined
&&
fileCount
>
1000
)
{
const
errMessage
:
string
=
`Too many files(
${
fileCount
}
found}) in
${
codeDir
}
,`
+
` please check if it's a valid code dir`
;
throw
new
Error
(
errMessage
);
}
if
(
!
fileNameValid
)
{
const
errMessage
:
string
=
`File name in
${
codeDir
}
is not valid, please check file names, only support digit number、alphabet and (.-_) in file name.`
;
throw
new
Error
(
errMessage
);
}
return
fileCount
;
}
/**
* crete a new directory
* @param directory
...
...
src/webui/package.json
View file @
f6343344
...
...
@@ -9,11 +9,12 @@
"copy-to-clipboard"
:
"^3.0.8"
,
"echarts"
:
"^4.1.0"
,
"echarts-for-react"
:
"^2.0.14"
,
"react"
:
"^16.
4
.2"
,
"react-dom"
:
"^16.
4
.2"
,
"react"
:
"^16.
7.0-alpha
.2"
,
"react-dom"
:
"^16.
7.0-alpha
.2"
,
"react-json-tree"
:
"^0.11.0"
,
"react-monaco-editor"
:
"^0.22.0"
,
"react-router"
:
"3.2.1"
,
"react-responsive"
:
"^7.0.0"
,
"react-scripts-ts-antd"
:
"2.17.0"
},
"scripts"
:
{
...
...
@@ -28,7 +29,8 @@
"@types/react"
:
"^16.4.17"
,
"@types/react-dom"
:
"^16.0.7"
,
"@types/react-json-tree"
:
"^0.6.8"
,
"@types/react-responsive"
:
"^3.0.3"
,
"@types/react-router"
:
"3.0.15"
,
"typescript"
:
"^3.0.1"
}
}
}
\ No newline at end of file
src/webui/src/App.css
View file @
f6343344
...
...
@@ -15,9 +15,7 @@
border-right
:
1px
solid
#ccc
;
z-index
:
1000
;
}
.headerCon
{
min-width
:
1024px
;
}
.contentBox
{
width
:
100%
;
}
...
...
@@ -29,5 +27,3 @@
margin-bottom
:
30px
;
background
:
#fff
;
}
src/webui/src/App.tsx
View file @
f6343344
...
...
@@ -3,20 +3,59 @@ import { Row, Col } from 'antd';
import
'
./App.css
'
;
import
SlideBar
from
'
./components/SlideBar
'
;
class
App
extends
React
.
Component
<
{},
{}
>
{
interface
AppState
{
interval
:
number
;
whichPageToFresh
:
string
;
}
class
App
extends
React
.
Component
<
{},
AppState
>
{
public
_isMounted
:
boolean
;
constructor
(
props
:
{})
{
super
(
props
);
this
.
state
=
{
interval
:
10
,
// sendons
whichPageToFresh
:
''
};
}
changeInterval
=
(
interval
:
number
)
=>
{
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
interval
:
interval
}));
}
}
changeFresh
=
(
fresh
:
string
)
=>
{
// interval * 1000
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
whichPageToFresh
:
fresh
}));
}
}
componentDidMount
()
{
this
.
_isMounted
=
true
;
}
componentWillUnmount
()
{
this
.
_isMounted
=
false
;
}
render
()
{
const
{
interval
,
whichPageToFresh
}
=
this
.
state
;
const
reactPropsChildren
=
React
.
Children
.
map
(
this
.
props
.
children
,
child
=>
// tslint:disable-next-line:no-any
React
.
cloneElement
(
child
as
React
.
ReactElement
<
any
>
,
{
interval
,
whichPageToFresh
})
);
return
(
<
Row
className
=
"nni"
style
=
{
{
minHeight
:
window
.
innerHeight
}
}
>
<
Row
className
=
"nni"
style
=
{
{
minHeight
:
window
.
innerHeight
}
}
>
<
Row
className
=
"header"
>
<
Col
span
=
{
1
}
/>
<
Col
className
=
"headerCon"
span
=
{
22
}
>
<
SlideBar
/>
<
SlideBar
changeInterval
=
{
this
.
changeInterval
}
changeFresh
=
{
this
.
changeFresh
}
/>
</
Col
>
<
Col
span
=
{
1
}
/>
</
Row
>
<
Row
className
=
"contentBox"
>
<
Row
className
=
"content"
>
{
this
.
p
rops
.
c
hildren
}
{
reactP
rops
C
hildren
}
</
Row
>
</
Row
>
</
Row
>
...
...
src/webui/src/components/Overview.tsx
View file @
f6343344
...
...
@@ -39,13 +39,18 @@ interface OverviewState {
isMultiPhase
:
boolean
;
}
class
Overview
extends
React
.
Component
<
{},
OverviewState
>
{
interface
OverviewProps
{
interval
:
number
;
// user select
whichPageToFresh
:
string
;
}
class
Overview
extends
React
.
Component
<
OverviewProps
,
OverviewState
>
{
public
_isMounted
=
false
;
public
intervalID
=
0
;
public
intervalProfile
=
1
;
constructor
(
props
:
{}
)
{
constructor
(
props
:
OverviewProps
)
{
super
(
props
);
this
.
state
=
{
searchSpace
:
{},
...
...
@@ -377,17 +382,19 @@ class Overview extends React.Component<{}, OverviewState> {
data
:
accarr
}]
};
this
.
setState
({
accuracyData
:
accOption
},
()
=>
{
if
(
accarr
.
length
===
0
)
{
this
.
setState
({
accNodata
:
'
No data
'
});
}
else
{
this
.
setState
({
accNodata
:
''
});
}
});
if
(
this
.
_isMounted
)
{
this
.
setState
({
accuracyData
:
accOption
},
()
=>
{
if
(
accarr
.
length
===
0
)
{
this
.
setState
({
accNodata
:
'
No data
'
});
}
else
{
this
.
setState
({
accNodata
:
''
});
}
});
}
}
clickMaxTop
=
(
event
:
React
.
SyntheticEvent
<
EventTarget
>
)
=>
{
...
...
@@ -405,23 +412,39 @@ class Overview extends React.Component<{}, OverviewState> {
isOffInterval
=
()
=>
{
const
{
status
}
=
this
.
state
;
switch
(
status
)
{
case
'
DONE
'
:
case
'
ERROR
'
:
case
'
STOPPED
'
:
window
.
clearInterval
(
this
.
intervalID
);
window
.
clearInterval
(
this
.
intervalProfile
);
break
;
default
:
const
{
interval
}
=
this
.
props
;
if
(
status
===
'
DONE
'
||
status
===
'
ERROR
'
||
status
===
'
STOPPED
'
||
interval
===
0
)
{
window
.
clearInterval
(
this
.
intervalID
);
window
.
clearInterval
(
this
.
intervalProfile
);
return
;
}
}
componentWillReceiveProps
(
nextProps
:
OverviewProps
)
{
const
{
interval
,
whichPageToFresh
}
=
nextProps
;
window
.
clearInterval
(
this
.
intervalID
);
window
.
clearInterval
(
this
.
intervalProfile
);
if
(
whichPageToFresh
.
includes
(
'
/oview
'
))
{
this
.
showTrials
();
this
.
showSessionPro
();
}
if
(
interval
!==
0
)
{
this
.
intervalID
=
window
.
setInterval
(
this
.
showTrials
,
interval
*
1000
);
this
.
intervalProfile
=
window
.
setInterval
(
this
.
showSessionPro
,
interval
*
1000
);
}
}
componentDidMount
()
{
this
.
_isMounted
=
true
;
this
.
showSessionPro
()
;
const
{
interval
}
=
this
.
props
;
this
.
showTrials
();
this
.
intervalID
=
window
.
setInterval
(
this
.
showTrials
,
10000
);
this
.
intervalProfile
=
window
.
setInterval
(
this
.
showSessionPro
,
60000
);
this
.
showSessionPro
();
if
(
interval
!==
0
)
{
this
.
intervalID
=
window
.
setInterval
(
this
.
showTrials
,
interval
*
1000
);
this
.
intervalProfile
=
window
.
setInterval
(
this
.
showSessionPro
,
interval
*
1000
);
}
}
componentWillUnmount
()
{
...
...
@@ -447,7 +470,7 @@ class Overview extends React.Component<{}, OverviewState> {
</
Row
>
<
Row
className
=
"overMessage"
>
{
/* status graph */
}
<
Col
span
=
{
9
}
className
=
"prograph overviewBoder"
>
<
Col
span
=
{
9
}
className
=
"prograph overviewBoder
cc
"
>
<
Title1
text
=
"Status"
icon
=
"5.png"
/>
<
Progressed
trialNumber
=
{
trialNumber
}
...
...
@@ -459,13 +482,13 @@ class Overview extends React.Component<{}, OverviewState> {
/>
</
Col
>
{
/* experiment parameters search space tuner assessor... */
}
<
Col
span
=
{
7
}
className
=
"overviewBoder"
>
<
Col
span
=
{
7
}
className
=
"overviewBoder
cc
"
>
<
Title1
text
=
"Search space"
icon
=
"10.png"
/>
<
Row
className
=
"experiment"
>
<
SearchSpace
searchSpace
=
{
searchSpace
}
/>
</
Row
>
</
Col
>
<
Col
span
=
{
8
}
className
=
"overviewBoder"
>
<
Col
span
=
{
8
}
className
=
"overviewBoder
cc
"
>
<
Title1
text
=
"Profile"
icon
=
"4.png"
/>
<
Row
className
=
"experiment"
>
{
/* the scroll bar all the trial profile in the searchSpace div*/
}
...
...
src/webui/src/components/SlideBar.tsx
View file @
f6343344
This diff is collapsed.
Click to expand it.
src/webui/src/components/TrialsDetail.tsx
View file @
f6343344
...
...
@@ -33,7 +33,12 @@ interface TrialDetailState {
intermediateCounts
:
number
;
}
class
TrialsDetail
extends
React
.
Component
<
{},
TrialDetailState
>
{
interface
TrialsDetailProps
{
interval
:
number
;
whichPageToFresh
:
string
;
}
class
TrialsDetail
extends
React
.
Component
<
TrialsDetailProps
,
TrialDetailState
>
{
public
_isMounted
=
false
;
public
interAccuracy
=
0
;
...
...
@@ -61,7 +66,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
</
div
>
);
constructor
(
props
:
{}
)
{
constructor
(
props
:
TrialsDetailProps
)
{
super
(
props
);
this
.
state
=
{
...
...
@@ -227,21 +232,24 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
// close timer
isOffIntervals
=
()
=>
{
axios
(
`
${
MANAGER_IP
}
/check-status`
,
{
method
:
'
GET
'
})
.
then
(
res
=>
{
if
(
res
.
status
===
200
&&
this
.
_isMounted
)
{
switch
(
res
.
data
.
status
)
{
case
'
DONE
'
:
case
'
ERROR
'
:
case
'
STOPPED
'
:
const
{
interval
}
=
this
.
props
;
if
(
interval
===
0
)
{
window
.
clearInterval
(
this
.
interTableList
);
return
;
}
else
{
axios
(
`
${
MANAGER_IP
}
/check-status`
,
{
method
:
'
GET
'
})
.
then
(
res
=>
{
if
(
res
.
status
===
200
&&
this
.
_isMounted
)
{
const
expStatus
=
res
.
data
.
status
;
if
(
expStatus
===
'
DONE
'
||
expStatus
===
'
ERROR
'
||
expStatus
===
'
STOPPED
'
)
{
window
.
clearInterval
(
this
.
interTableList
);
b
re
ak
;
default
:
re
turn
;
}
}
}
});
}
);
}
}
handleEntriesSelect
=
(
value
:
string
)
=>
{
...
...
@@ -304,11 +312,23 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
});
}
componentWillReceiveProps
(
nextProps
:
TrialsDetailProps
)
{
const
{
interval
,
whichPageToFresh
}
=
nextProps
;
window
.
clearInterval
(
this
.
interTableList
);
if
(
interval
!==
0
)
{
this
.
interTableList
=
window
.
setInterval
(
this
.
getDetailSource
,
interval
*
1000
);
}
if
(
whichPageToFresh
.
includes
(
'
/detail
'
))
{
this
.
getDetailSource
();
}
}
componentDidMount
()
{
this
.
_isMounted
=
true
;
const
{
interval
}
=
this
.
props
;
this
.
getDetailSource
();
this
.
interTableList
=
window
.
setInterval
(
this
.
getDetailSource
,
1
0
000
);
this
.
interTableList
=
window
.
setInterval
(
this
.
getDetailSource
,
interval
*
1000
);
this
.
checkExperimentPlatform
();
}
...
...
@@ -329,7 +349,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
<
div
>
<
div
className
=
"trial"
id
=
"tabsty"
>
<
Tabs
type
=
"card"
onChange
=
{
this
.
handleWhichTabs
}
>
{
/* <TabPane tab={this.titleOfacc} key="1" destroyInactiveTabPane={true}> */
}
<
TabPane
tab
=
{
this
.
titleOfacc
}
key
=
"1"
>
<
Row
className
=
"graph"
>
<
DefaultPoint
...
...
@@ -350,7 +369,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
</
TabPane
>
<
TabPane
tab
=
{
this
.
titleOfDuration
}
key
=
"3"
>
<
Duration
source
=
{
source
}
whichGraph
=
{
whichGraph
}
/>
{
/* <Duration source={source} whichGraph={whichGraph} clickCounts={durationCounts} /> */
}
</
TabPane
>
<
TabPane
tab
=
{
this
.
titleOfIntermediate
}
key
=
"4"
>
<
Intermediate
source
=
{
source
}
whichGraph
=
{
whichGraph
}
/>
...
...
src/webui/src/static/style/slideBar.scss
View file @
f6343344
$barHeight
:
56px
;
/* drowdown and select default bgcolor */
$drowBgColor
:
#f2f2f2
;
/* drowdown and select hover bgcolor */
$drowHoverBgColor
:
#e2e2e2
;
.nav
{
list-style
:
none
;
width
:
9
4
%
;
width
:
9
5
%
;
height
:
$barHeight
;
margin
:
0
auto
;
position
:
relative
;
.tab
{
font-family
:
'Segoe'
;
line-height
:
$barHeight
;
...
...
@@ -14,7 +19,7 @@ $barHeight: 56px;
}
}
.firstTab
{
margin
:
0
3
2px
;
margin
:
0
2
0
px
;
}
.logo
{
margin-top
:
2px
;
...
...
@@ -28,17 +33,26 @@ $barHeight: 56px;
}
.feedback
{
text-align
:
right
;
position
:
fixed
;
right
:
19%
;
line-height
:
$barHeight
;
font-size
:
16px
;
color
:
#fff
;
.fresh
{
span
{
margin
:
0
10px
0
3px
;
}
}
.fresh
:hover
{
cursor
:
pointer
;
}
a
{
color
:
#fff
;
text-decoration
:
none
;
margin-left
:
10px
;
}
img
{
width
:
2
4
px
;
width
:
2
0
px
;
margin-right
:
8px
;
}
.version
{
...
...
@@ -51,4 +65,66 @@ $barHeight: 56px;
}
.dropdown
{
margin-right
:
10px
;
}
\ No newline at end of file
/* make dropdown content box position in blue bar bottom */
padding-bottom
:
14px
;
}
.interval
{
position
:
fixed
;
right
:
7%
;
top
:
12px
;
.ant-select-selection
{
background-color
:
transparent
;
border
:
none
;
color
:
#fff
;
outline
:
none
;
font-size
:
16px
;
}
.ant-select-arrow
{
color
:
#fff
;
}
}
/* set select bgcolor */
.ant-select-dropdown-menu
{
background-color
:
$drowBgColor
;
}
.ant-select-dropdown-menu-item
:hover
{
background-color
:
$drowHoverBgColor
;
}
.ant-select-dropdown-menu-item-active
{
background-color
:
transparent
;
}
/* set dropdown bgcolor */
.ant-dropdown
{
.ant-dropdown-menu
{
padding
:
0
;
background-color
:
$drowBgColor
;
border-radius
:
0
;
.ant-dropdown-menu-item
:hover
{
background-color
:
$drowHoverBgColor
;
}
}
}
/* nav style*/
.little
{
width
:
100%
;
.menu
{
.show
{
display
:
block
;
}
.hide
{
display
:
none
;
}
.more
{
color
:
#fff
;
font-size
:
24px
;
margin-top
:
16px
;
}
.more
:hover
{
cursor
:
pointer
;
}
}
.logo
{
text-align
:
center
;
}
}
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