Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
nomad-lab
nomad-FAIR
Commits
658bdddb
Commit
658bdddb
authored
Sep 07, 2018
by
Markus Scheidgen
Browse files
Added upload cmd gui, partially.
parent
3842da5c
Changes
8
Hide whitespace changes
Inline
Side-by-side
gui/package.json
View file @
658bdddb
...
...
@@ -10,6 +10,7 @@
"fetch"
:
"^1.1.0"
,
"html-to-react"
:
"^1.3.3"
,
"react"
:
"^16.4.2"
,
"react-copy-to-clipboard"
:
"^5.0.1"
,
"react-dom"
:
"^16.4.2"
,
"react-dropzone"
:
"^5.0.1"
,
"react-highlight"
:
"^0.12.0"
,
...
...
gui/src/components/Upload.js
View file @
658bdddb
...
...
@@ -131,11 +131,16 @@ class Upload extends React.Component {
return
(
<
div
className
=
{
classes
.
title
}
>
<
Typography
variant
=
"
title
"
>
{
name
||
upload_id
}
<
/Typography
>
<
Typography
variant
=
"
subheading
"
>
{
new
Date
(
Date
.
parse
(
create_time
)).
toLocaleString
()}
{
name
||
new
Date
(
Date
.
parse
(
create_time
)).
toLocaleString
()}
<
/Typography
>
{
name
?
<
Typography
variant
=
"
subheading
"
>
{
new
Date
(
Date
.
parse
(
create_time
)).
toLocaleString
()}
<
/Typography
>
:
'
this upload has no name
'
}
<
/div
>
)
}
...
...
gui/src/components/Uploads.js
View file @
658bdddb
...
...
@@ -2,7 +2,14 @@ import React from 'react'
import
PropTypes
from
'
prop-types
'
import
Markdown
from
'
./Markdown
'
import
{
withStyles
,
Paper
,
IconButton
,
FormGroup
,
Checkbox
,
FormControlLabel
,
FormLabel
,
LinearProgress
}
from
'
@material-ui/core
'
LinearProgress
,
FormControl
,
InputLabel
,
Input
,
FormHelperText
,
Button
,
Popover
,
Typography
}
from
'
@material-ui/core
'
import
UploadIcon
from
'
@material-ui/icons/CloudUpload
'
import
Dropzone
from
'
react-dropzone
'
import
api
from
'
../api
'
...
...
@@ -11,6 +18,7 @@ import { withErrors } from './errors'
import
{
compose
}
from
'
recompose
'
import
DeleteIcon
from
'
@material-ui/icons/Delete
'
import
CheckIcon
from
'
@material-ui/icons/Check
'
import
AddIcon
from
'
@material-ui/icons/Add
'
import
CommingSoon
from
'
./CommingSoon
'
class
Uploads
extends
React
.
Component
{
...
...
@@ -48,11 +56,31 @@ class Uploads extends React.Component {
},
uploads
:
{
marginTop
:
theme
.
spacing
.
unit
*
2
},
uploadFormControl
:
{
margin
:
theme
.
spacing
.
unit
*
2
,
},
button
:
{
margin
:
theme
.
spacing
.
unit
,
},
rightIcon
:
{
marginLeft
:
theme
.
spacing
.
unit
,
},
uploadNameInput
:
{
width
:
300
},
uploadPopper
:
{
margin
:
theme
.
spacing
.
unit
*
2
},
uploadCommand
:
{
fontFamily
:
'
Roboto mono, monospace
'
,
marginTop
:
theme
.
spacing
.
unit
*
2
}
})
state
=
{
uploads
:
null
,
selectedUploads
:
[],
loading
:
true
,
acceptCommingSoon
:
false
uploads
:
null
,
selectedUploads
:
[],
loading
:
true
,
acceptCommingSoon
:
false
,
uploadName
:
''
,
uploadCommand
:
null
,
showUploadCommand
:
false
,
uploadPopperAnchor
:
null
}
componentDidMount
()
{
...
...
@@ -72,6 +100,29 @@ class Uploads extends React.Component {
})
}
onCreateUploadCmdClicked
(
event
)
{
const
existingUpload
=
this
.
state
.
uploads
.
find
(
upload
=>
upload
.
name
===
this
.
state
.
uploadName
)
if
(
existingUpload
)
{
const
upload
=
existingUpload
this
.
setState
({
uploadCommand
:
upload
.
upload_command
,
showUploadCommand
:
true
,
uploadPopperAnchor
:
event
.
currentTarget
})
}
else
{
api
.
createUpload
(
this
.
state
.
uploadName
)
.
then
(
upload
=>
{
this
.
setState
({
uploads
:
[...
this
.
state
.
uploads
,
upload
],
uploadCommand
:
upload
.
upload_command
,
showUploadCommand
:
true
,
uploadPopperAnchor
:
event
.
currentTarget
})
})
.
catch
(
error
=>
{
this
.
props
.
raiseError
(
error
)
})
}
}
onDeleteClicked
()
{
this
.
setState
({
loading
:
true
})
Promise
.
all
(
this
.
state
.
selectedUploads
.
map
(
upload
=>
api
.
deleteUpload
(
upload
.
upload_id
)))
...
...
@@ -172,16 +223,19 @@ class Uploads extends React.Component {
render
()
{
const
{
classes
}
=
this
.
props
const
{
showUploadCommand
,
uploadCommand
,
uploadPopperAnchor
}
=
this
.
state
return
(
<
div
className
=
{
classes
.
root
}
>
<
Markdown
>
{
`
## Upload your own data
You can upload your own data. Have your code output ready in a popular archive
format (e.g.
\`
*.zip
\`
or
\`
*.tar.gz
\`
)
and drop it below
. Your upload can
format (e.g.
\`
*.zip
\`
or
\`
*.tar.gz
\`
).
Your upload can
comprise the output of multiple runs, even of different codes. Don't worry, nomad
will find it.
### Browser upload
Just drop your file below.
`
}
<
/Markdown
>
<
Paper
>
<
Dropzone
...
...
@@ -195,6 +249,49 @@ class Uploads extends React.Component {
<
UploadIcon
style
=
{{
fontSize
:
36
}}
/
>
<
/Dropzone
>
<
/Paper
>
<
Markdown
>
{
`
### Command line upload
Alternatively, you can upload your file via
\`
curl
\`
. The name is
optional, but it will help you to track your uploads.
`
}
<
/Markdown
>
<
Paper
>
<
FormControl
className
=
{
classes
.
uploadFormControl
}
>
<
InputLabel
htmlFor
=
"
name-helper
"
>
Upload
name
<
/InputLabel
>
<
Input
className
=
{
classes
.
uploadNameInput
}
id
=
"
name-helper
"
value
=
{
this
.
state
.
uploadName
}
onChange
=
{(
event
)
=>
this
.
setState
({
uploadName
:
event
.
target
.
value
})}
/
>
<
FormHelperText
id
=
"
name-helper-text
"
>
With
out
name
,
you
only
see
the
time
<
/FormHelperText
>
<
/FormControl
>
<
FormControl
className
=
{
classes
.
uploadFormControl
}
>
<
Button
color
=
"
primary
"
className
=
{
classes
.
button
}
variant
=
"
contained
"
onClick
=
{
this
.
onCreateUploadCmdClicked
.
bind
(
this
)}
>
add
upload
<
AddIcon
className
=
{
classes
.
rightIcon
}
/
>
<
/Button
>
<
Popover
id
=
"
upload-command-popper
"
onClose
=
{()
=>
this
.
setState
({
showUploadCommand
:
false
})}
open
=
{
showUploadCommand
}
anchorEl
=
{
uploadPopperAnchor
}
anchorOrigin
=
{{
vertical
:
'
bottom
'
,
horizontal
:
'
center
'
,
}}
transformOrigin
=
{{
vertical
:
'
top
'
,
horizontal
:
'
center
'
,
}}
>
<
div
className
=
{
classes
.
uploadPopper
}
>
<
Typography
>
Copy
and
use
the
following
command
.
Don
'
t forget to replace the file name.:</Typography>
<Typography className={classes.uploadCommand}>{uploadCommand}</Typography>
</div>
</Popover>
</FormControl>
</Paper>
{this.renderUploads()}
{this.state.loading ? <LinearProgress/> :
''
}
...
...
gui/yarn.lock
View file @
658bdddb
...
...
@@ -1898,6 +1898,12 @@ copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
copy-to-clipboard@^3:
version "3.0.8"
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz#f4e82f4a8830dce4666b7eb8ded0c9bcc313aba9"
dependencies:
toggle-selection "^1.0.3"
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
...
...
@@ -6156,6 +6162,13 @@ react-base16-styling@^0.6.0:
lodash.flow "^3.3.0"
pure-color "^1.2.0"
react-copy-to-clipboard@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.1.tgz#8eae107bb400be73132ed3b6a7b4fb156090208e"
dependencies:
copy-to-clipboard "^3"
prop-types "^15.5.8"
react-dev-utils@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-5.0.1.tgz#1f396e161fe44b595db1b186a40067289bf06613"
...
...
@@ -7385,6 +7398,10 @@ to-regex@^3.0.1, to-regex@^3.0.2:
regex-not "^1.0.2"
safe-regex "^1.1.0"
toggle-selection@^1.0.3:
version "1.0.6"
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
toposort@^1.0.0:
version "1.0.7"
resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029"
...
...
nomad/files.py
View file @
658bdddb
...
...
@@ -106,8 +106,7 @@ def create_curl_upload_cmd(presigned_url: str, file_dummy: str='<ZIPFILE>') -> s
Returns:
The curl shell command with correct method, url, headers, etc.
"""
headers
=
'Content-Type: application/octet-steam'
return
'curl -X PUT "%s" -H "%s" -F file=@%s'
%
(
presigned_url
,
headers
,
file_dummy
)
return
'curl "%s" --upload-file %s'
%
(
presigned_url
,
file_dummy
)
def
upload_put_handler
(
func
:
Callable
[[
str
],
None
])
->
Callable
[[],
None
]:
...
...
nomad/processing/data.py
View file @
658bdddb
...
...
@@ -202,6 +202,7 @@ class Upload(Proc):
is_private
=
BooleanField
(
default
=
False
)
presigned_url
=
StringField
()
upload_command
=
StringField
()
upload_time
=
DateTimeField
()
upload_hash
=
StringField
(
default
=
None
)
...
...
@@ -268,6 +269,7 @@ class Upload(Proc):
"""
self
=
super
().
create
(
**
kwargs
)
self
.
presigned_url
=
files
.
get_presigned_upload_url
(
self
.
upload_id
)
self
.
upload_command
=
files
.
create_curl_upload_cmd
(
self
.
presigned_url
,
'your_file'
)
self
.
_continue_with
(
'uploading'
)
return
self
...
...
@@ -285,7 +287,8 @@ class Upload(Proc):
'name'
:
self
.
name
,
'additional_metadata'
:
self
.
additional_metadata
,
'upload_id'
:
self
.
upload_id
,
'presigned_url'
:
files
.
external_objects_url
(
self
.
presigned_url
),
'presigned_url'
:
self
.
presigned_url
,
'upload_command'
:
self
.
upload_command
,
'upload_time'
:
self
.
upload_time
.
isoformat
()
if
self
.
upload_time
is
not
None
else
None
,
'is_stale'
:
self
.
is_stale
,
}
...
...
tests/test_api.py
View file @
658bdddb
...
...
@@ -55,6 +55,7 @@ def assert_upload(upload_json_str, id=None, **kwargs):
assert
id
==
data
[
'upload_id'
]
assert
'create_time'
in
data
assert
'presigned_url'
in
data
assert
'upload_command'
in
data
for
key
,
value
in
kwargs
.
items
():
assert
data
.
get
(
key
,
None
)
==
value
...
...
tests/test_files.py
View file @
658bdddb
...
...
@@ -108,7 +108,7 @@ def test_presigned_url(upload_id):
subprocess
.
call
(
shlex
.
split
(
cmd
))
stat
=
files
.
_client
.
stat_object
(
config
.
files
.
uploads_bucket
,
upload_id
)
assert
stat
.
content_type
.
startswith
(
'application/octet-steam'
)
assert
stat
is
not
None
def
test_upload
(
uploaded_id
:
str
):
...
...
Write
Preview
Supports
Markdown
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