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
nomad-lab
nomad-FAIR
Commits
b1593dd2
Commit
b1593dd2
authored
May 11, 2021
by
Markus Scheidgen
Browse files
Rewrote the apiV1.js to be more in a functional components react style.
parent
ba455f16
Pipeline
#101256
passed with stages
in 25 minutes and 30 seconds
Changes
9
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
gui/src/components/App.js
View file @
b1593dd2
...
...
@@ -28,7 +28,6 @@ import { KeycloakProvider } from 'react-keycloak'
import
{
MuiThemeProvider
}
from
'
@material-ui/core/styles
'
import
{
ApiProvider
}
from
'
./api
'
import
{
ErrorSnacks
,
ErrorBoundary
}
from
'
./errors
'
import
{
ApiV1Provider
}
from
'
./apiV1
'
import
Navigation
from
'
./nav/Navigation
'
export
const
matomo
=
matomoEnabled
?
PiwikReactRouter
({
...
...
@@ -55,11 +54,9 @@ export default function App() {
<
ErrorSnacks
>
<
ErrorBoundary
>
<
RecoilRoot
>
<
ApiV1Provider
>
<
ApiProvider
>
<
Navigation
/>
<
/ApiProvider
>
<
/ApiV1Provider
>
<
ApiProvider
>
<
Navigation
/>
<
/ApiProvider
>
<
/RecoilRoot
>
<
/ErrorBoundary
>
<
/ErrorSnacks
>
...
...
gui/src/components/apiV1.js
View file @
b1593dd2
...
...
@@ -15,18 +15,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import
React
,
{
useContext
,
useEffect
,
useCallback
,
useRef
}
from
'
react
'
import
React
from
'
react
'
import
PropTypes
from
'
prop-types
'
import
{
withErrors
}
from
'
./errors
'
import
{
apiBase
}
from
'
../config
'
import
{
Typography
,
withStyles
}
from
'
@material-ui/core
'
import
{
makeStyles
,
Typography
}
from
'
@material-ui/core
'
import
LoginLogout
from
'
./LoginLogout
'
import
{
compose
}
from
'
recompose
'
import
{
withKeycloak
}
from
'
react-keycloak
'
import
{
useKeycloak
}
from
'
react-keycloak
'
import
axios
from
'
axios
'
export
const
apiContextV1
=
React
.
createContext
()
export
class
DoesNotExist
extends
Error
{
constructor
(
msg
)
{
super
(
msg
)
...
...
@@ -228,236 +224,49 @@ function parse(result) {
}
}
export
class
ApiProviderComponent
extends
React
.
Component
{
static
propTypes
=
{
children
:
PropTypes
.
oneOfType
([
PropTypes
.
arrayOf
(
PropTypes
.
node
),
PropTypes
.
node
]).
isRequired
,
raiseError
:
PropTypes
.
func
.
isRequired
,
keycloak
:
PropTypes
.
object
.
isRequired
,
keycloakInitialized
:
PropTypes
.
bool
}
constructor
(
props
)
{
super
(
props
)
this
.
onToken
=
this
.
onToken
.
bind
(
this
)
}
onToken
(
token
)
{
// console.log(token)
}
update
()
{
const
{
keycloak
}
=
this
.
props
this
.
setState
({
apiV1
:
this
.
createApi
(
keycloak
)})
if
(
keycloak
.
token
)
{
keycloak
.
loadUserInfo
()
.
success
(
user
=>
{
this
.
setState
({
user
:
user
})
})
.
error
(
error
=>
{
this
.
props
.
raiseError
(
error
)
})
}
}
componentDidMount
()
{
this
.
update
()
}
componentDidUpdate
(
prevProps
)
{
if
(
this
.
props
.
keycloakInitialized
!==
prevProps
.
keycloakInitialized
)
{
this
.
update
()
}
}
let
api
=
null
createApi
(
keycloak
)
{
const
api
=
new
Api
(
keycloak
)
return
api
}
export
function
useApi
()
{
const
[
keycloak
]
=
useKeycloak
()
state
=
{
api
V1
:
null
if
(
!
api
||
api
.
keycloak
!==
keycloak
)
{
api
=
new
Api
(
keycloak
)
}
render
()
{
const
{
children
}
=
this
.
props
return
(
<
apiContextV1
.
Provider
value
=
{
this
.
state
}
>
{
children
}
<
/apiContextV1.Provider
>
)
}
return
api
}
class
LoginRequiredUnstyled
extends
React
.
Component
{
static
propTypes
=
{
classes
:
PropTypes
.
object
.
isRequired
,
message
:
PropTypes
.
string
}
static
styles
=
theme
=>
({
root
:
{
display
:
'
flex
'
,
alignItems
:
'
center
'
,
padding
:
theme
.
spacing
(
2
),
'
& p
'
:
{
marginRight
:
theme
.
spacing
(
2
)
}
}
})
render
()
{
const
{
classes
,
message
}
=
this
.
props
let
loginMessage
=
''
if
(
message
)
{
loginMessage
=
<
Typography
>
{
this
.
props
.
message
}
<
/Typography
>
const
useLoginRequiredStyles
=
makeStyles
(
theme
=>
({
root
:
{
padding
:
theme
.
spacing
(
2
),
display
:
'
flex
'
,
alignItems
:
'
center
'
,
'
& p
'
:
{
marginRight
:
theme
.
spacing
(
1
)
}
return
(
<
div
className
=
{
classes
.
root
}
>
<
div
>
{
loginMessage
}
<
/div
>
<
LoginLogout
color
=
"
primary
"
/>
<
/div
>
)
}
}
export
function
DisableOnLoading
({
children
})
{
const
containerRef
=
useRef
(
null
)
const
{
apiV1
}
=
useContext
(
apiContextV1
)
const
handleLoading
=
useCallback
((
loading
)
=>
{
const
enable
=
loading
?
'
none
'
:
''
containerRef
.
current
.
style
.
pointerEvents
=
enable
containerRef
.
current
.
style
.
userSelects
=
enable
},
[])
useEffect
(()
=>
{
apiV1
.
onLoading
(
handleLoading
)
return
()
=>
{
apiV1
.
removeOnLoading
(
handleLoading
)
}
},
[
apiV1
,
handleLoading
])
return
<
div
ref
=
{
containerRef
}
>
{
children
}
<
/div
>
}
DisableOnLoading
.
propTypes
=
{
children
:
PropTypes
.
any
.
isRequired
}
export
const
ApiV1Provider
=
compose
(
withKeycloak
,
withErrors
)(
ApiProviderComponent
)
const
LoginRequired
=
withStyles
(
LoginRequiredUnstyled
.
styles
)(
LoginRequiredUnstyled
)
const
__reauthorize_trigger_changes
=
[
'
apiV1
'
,
'
calcId
'
,
'
uploadId
'
,
'
calc_id
'
,
'
upload_id
'
]
class
WithApiComponent
extends
React
.
Component
{
static
propTypes
=
{
raiseError
:
PropTypes
.
func
.
isRequired
,
loginRequired
:
PropTypes
.
bool
,
showErrorPage
:
PropTypes
.
bool
,
loginMessage
:
PropTypes
.
string
,
api
:
PropTypes
.
object
,
user
:
PropTypes
.
object
,
Component
:
PropTypes
.
any
}
state
=
{
notAuthorized
:
false
}
constructor
(
props
)
{
super
(
props
)
this
.
raiseError
=
this
.
raiseError
.
bind
(
this
)
}
componentDidUpdate
(
prevProps
)
{
if
(
__reauthorize_trigger_changes
.
find
(
key
=>
this
.
props
[
key
]
!==
prevProps
[
key
]))
{
this
.
setState
({
notAuthorized
:
false
})
}
}
raiseError
(
error
)
{
const
{
raiseError
,
showErrorPage
}
=
this
.
props
console
.
error
(
error
)
if
(
!
showErrorPage
)
{
raiseError
(
error
)
}
else
{
if
(
error
.
name
===
'
NotAuthorized
'
)
{
this
.
setState
({
notAuthorized
:
true
})
}
else
{
raiseError
(
error
)
}
}
}
render
()
{
const
{
raiseError
,
loginRequired
,
loginMessage
,
Component
,
...
rest
}
=
this
.
props
const
{
apiV1
,
keycloak
}
=
rest
const
{
notAuthorized
}
=
this
.
state
if
(
notAuthorized
)
{
if
(
keycloak
.
authenticated
)
{
return
(
<
div
style
=
{{
marginTop
:
24
}}
>
<
Typography
variant
=
"
h6
"
>
Not
Authorized
<
/Typography
>
<
Typography
>
You
are
not
authorized
to
access
this
information
.
If
someone
send
you
a
link
to
this
data
,
ask
the
authors
to
make
the
data
publicly
available
or
share
it
with
you
.
<
/Typography
>
<
/div
>
)
}
else
{
return
(
<
LoginRequired
message
=
"
You need to be logged in to access this information.
"
/>
)
}
}
else
{
if
(
apiV1
)
{
if
(
keycloak
.
authenticated
||
!
loginRequired
)
{
return
<
Component
{...
rest
}
raiseError
=
{
this
.
raiseError
}
/
>
}
else
{
return
<
LoginRequired
message
=
{
loginMessage
}
/
>
}
}
else
{
return
''
}
}
}))
export
function
LoginRequired
({
message
,
children
})
{
const
classes
=
useLoginRequiredStyles
()
const
api
=
useApi
()
if
(
api
.
keycloak
.
authenticated
)
{
return
<
React
.
Fragment
>
{
children
}
<
/React.Fragment
>
}
else
{
return
<
div
className
=
{
classes
.
root
}
>
<
Typography
>
{
message
||
'
You have to login to use this functionality.
'
}
<
/Typography
>
<
LoginLogout
color
=
"
primary
"
/>
<
/div
>
}
}
const
WithKeycloakWithApiComponent
=
withKeycloak
(
WithApiComponent
)
/**
* HOC that will check the API connectivity before rendering a component.
*
* @param {bool} loginRequired Set to true if component should not be displayed
* without login.
* @param {bool} showErrorPage
* @param {string} loginMessage The login message to show.
*/
export
function
withApiV1
(
loginRequired
,
showErrorPage
,
loginMessage
)
{
return
function
(
Component
)
{
return
withErrors
(
props
=>
(
<
apiContextV1
.
Consumer
>
{
apiContext
=>
(
<
WithKeycloakWithApiComponent
loginRequired
=
{
loginRequired
}
loginMessage
=
{
loginMessage
}
showErrorPage
=
{
showErrorPage
}
Component
=
{
Component
}
{...
props
}
{...
apiContext
}
/
>
)}
<
/apiContextV1.Consumer
>
))
}
LoginRequired
.
propTypes
=
{
message
:
PropTypes
.
string
,
children
:
PropTypes
.
oneOfType
([
PropTypes
.
arrayOf
(
PropTypes
.
node
),
PropTypes
.
node
]).
isRequired
}
gui/src/components/dft/DFTEntryOverview.js
View file @
b1593dd2
...
...
@@ -21,7 +21,7 @@ import { useRecoilValue } from 'recoil'
import
{
Box
,
Card
,
CardContent
,
Grid
,
Typography
,
Link
,
makeStyles
,
Divider
}
from
'
@material-ui/core
'
import
_
from
'
lodash
'
import
{
apiContext
as
apiContextV0
}
from
'
../api
'
import
{
apiContextV1
}
from
'
../apiV1
'
import
{
useApi
}
from
'
../apiV1
'
import
{
ApiDialog
}
from
'
../ApiDialogButton
'
import
ElectronicProperties
from
'
../visualization/ElectronicProperties
'
import
VibrationalProperties
from
'
../visualization/VibrationalProperties
'
...
...
@@ -216,7 +216,7 @@ export default function DFTEntryOverview({data}) {
},
[
data
,
hasResults
])
const
apiV0
=
useContext
(
apiContextV0
).
api
const
apiV1
=
use
Context
(
apiContextV1
).
apiV1
const
apiV1
=
use
Api
()
const
{
raiseError
}
=
useContext
(
errorContext
)
const
[
dosElectronic
,
setDosElectronic
]
=
useState
(
availableProps
.
has
(
'
dos_electronic
'
)
?
null
:
false
)
const
[
bsElectronic
,
setBsElectronic
]
=
useState
(
availableProps
.
has
(
'
band_structure_electronic
'
)
?
null
:
false
)
...
...
gui/src/components/dft/DFTEntryOverview.spec.js
View file @
b1593dd2
...
...
@@ -18,17 +18,28 @@
import
React
from
'
react
'
import
'
regenerator-runtime/runtime
'
import
{
renderWithAPIRouter
}
from
'
../../testutils
'
import
DFTEntryOverview
from
'
./DFTEntryOverview
'
import
{
renderWithAPIRouter
,
archives
,
wait
}
from
'
../../testutils
'
import
{
screen
}
from
'
@testing-library/react
'
import
{
waitFor
,
within
}
from
'
@testing-library/dom
'
import
'
@testing-library/jest-dom/extend-expect
'
import
DFTEntryOverview
from
'
./DFTEntryOverview
'
import
{
repoDftBulk
,
repoDftBulkOld
,
archiveDftBulk
,
archiveDftBulkOld
}
from
'
../../../tests/DFTBulk
'
import
'
@testing-library/jest-dom/extend-expect
'
import
{
useApi
}
from
'
../apiV1
'
jest
.
mock
(
'
../apiV1
'
)
beforeAll
(()
=>
{
useApi
.
mockReturnValue
({
results
:
entry_id
=>
wait
(
archives
.
get
(
entry_id
))
})
})
afterAll
(()
=>
jest
.
unmock
(
'
../apiV1
'
))
async
function
testMaterialMethod
(
repo
,
archive
)
{
renderWithAPIRouter
(
...
...
gui/src/components/entry/OverviewView.js
View file @
b1593dd2
...
...
@@ -18,8 +18,7 @@
import
React
,
{
useContext
,
useState
,
useEffect
}
from
'
react
'
import
PropTypes
from
'
prop-types
'
import
{
domainComponents
}
from
'
../domainComponents
'
import
{
compose
}
from
'
recompose
'
import
{
withApiV1
}
from
'
../apiV1
'
import
{
useApi
}
from
'
../apiV1
'
import
{
EntryPageContent
}
from
'
./EntryPage
'
import
{
errorContext
}
from
'
../errors
'
import
{
Typography
,
makeStyles
}
from
'
@material-ui/core
'
...
...
@@ -47,16 +46,17 @@ const useStyles = makeStyles(theme => ({
/**
* Shows an informative overview about the selected entry.
*/
function
OverviewView
({
uploadId
,
entryId
,
apiV1
})
{
export
default
function
OverviewView
({
uploadId
,
entryId
})
{
const
classes
=
useStyles
()
const
{
raiseError
}
=
useContext
(
errorContext
)
const
[
entry
,
setEntry
]
=
useState
(
null
)
const
[
exists
,
setExists
]
=
useState
(
true
)
const
api
=
useApi
()
// When loaded for the first time, download calc data from the ElasticSearch
// index. It is used to decide the subview to show.
useEffect
(()
=>
{
api
V1
.
entry
(
entryId
).
then
(
data
=>
{
api
.
entry
(
entryId
).
then
(
data
=>
{
setEntry
(
data
)
}).
catch
(
error
=>
{
if
(
error
.
name
===
'
DoesNotExist
'
)
{
...
...
@@ -65,7 +65,7 @@ function OverviewView({uploadId, entryId, apiV1}) {
raiseError
(
error
)
}
})
},
[
api
V1
,
raiseError
,
entryId
,
setEntry
,
setExists
])
},
[
api
,
raiseError
,
entryId
,
setEntry
,
setExists
])
// The entry does not exist
if
(
!
exists
)
{
...
...
@@ -88,10 +88,5 @@ function OverviewView({uploadId, entryId, apiV1}) {
OverviewView
.
propTypes
=
{
uploadId
:
PropTypes
.
string
.
isRequired
,
entryId
:
PropTypes
.
string
.
isRequired
,
apiV1
:
PropTypes
.
object
.
isRequired
entryId
:
PropTypes
.
string
.
isRequired
}
export
default
compose
(
withApiV1
(
false
,
true
)
)(
OverviewView
)
gui/src/components/entry/RawFileView.js
View file @
b1593dd2
...
...
@@ -17,12 +17,11 @@
*/
import
React
,
{
useContext
,
useState
,
useEffect
}
from
'
react
'
import
PropTypes
from
'
prop-types
'
import
{
compose
}
from
'
recompose
'
import
{
Typography
,
makeStyles
}
from
'
@material-ui/core
'
import
{
withApiV1
}
from
'
../apiV1
'
import
{
domainComponents
}
from
'
../domainComponents
'
import
{
EntryPageContent
}
from
'
./EntryPage
'
import
{
errorContext
}
from
'
../errors
'
import
{
useApi
}
from
'
../apiV1
'
const
useStyles
=
makeStyles
(
theme
=>
({
error
:
{
...
...
@@ -30,17 +29,18 @@ const useStyles = makeStyles(theme => ({
}
}))
function
RawFileView
({
uploadId
,
entryId
,
apiV1
})
{
export
default
function
RawFileView
({
uploadId
,
entryId
})
{
const
classes
=
useStyles
()
const
{
raiseError
}
=
useContext
(
errorContext
)
const
[
state
,
setState
]
=
useState
({
entryData
:
null
,
doesNotExist
:
false
})
const
api
=
useApi
()
useEffect
(()
=>
{
setState
({
entryData
:
null
,
doesNotExist
:
false
})
},
[
setState
,
uploadId
,
entryId
])
useEffect
(()
=>
{
api
V1
.
entry
(
entryId
).
then
(
entry
=>
{
api
.
entry
(
entryId
).
then
(
entry
=>
{
setState
({
entryData
:
entry
.
data
,
doesNotExist
:
false
})
}).
catch
(
error
=>
{
if
(
error
.
name
===
'
DoesNotExist
'
)
{
...
...
@@ -50,7 +50,7 @@ function RawFileView({uploadId, entryId, apiV1}) {
raiseError
(
error
)
}
})
},
[
api
V1
,
raiseError
,
entryId
,
setState
])
},
[
api
,
raiseError
,
entryId
,
setState
])
const
entryData
=
state
.
entryData
||
{
uploadId
:
uploadId
,
entryId
:
entryId
}
const
domainComponent
=
entryData
.
domain
&&
domainComponents
[
entryData
.
domain
]
...
...
@@ -72,10 +72,5 @@ function RawFileView({uploadId, entryId, apiV1}) {
RawFileView
.
propTypes
=
{
uploadId
:
PropTypes
.
string
.
isRequired
,
entryId
:
PropTypes
.
string
.
isRequired
,
apiV1
:
PropTypes
.
object
.
isRequired
entryId
:
PropTypes
.
string
.
isRequired
}
export
default
compose
(
withApiV1
(
false
,
true
)
)(
RawFileView
)
gui/src/components/entry/RawFiles.js
View file @
b1593dd2
...
...
@@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import
React
,
{
useState
,
useCallback
,
useContext
,
useEffect
}
from
'
react
'
import
React
,
{
useState
,
useCallback
,
useEffect
}
from
'
react
'
import
PropTypes
from
'
prop-types
'
import
{
makeStyles
,
...
...
@@ -31,13 +31,13 @@ import {
}
from
'
@material-ui/core
'
import
DownloadIcon
from
'
@material-ui/icons/CloudDownload
'
import
{
withApi
}
from
'
../api
'
import
{
apiContextV1
}
from
'
../apiV1
'
import
{
compose
}
from
'
recompose
'
import
Download
from
'
./Download
'
import
ReloadIcon
from
'
@material-ui/icons/Cached
'
import
ViewIcon
from
'
@material-ui/icons/Search
'
import
InfiniteScroll
from
'
react-infinite-scroller
'
import
{
ScrollContext
}
from
'
../nav/Navigation
'
import
{
useApi
}
from
'
../apiV1
'
const
useStyles
=
makeStyles
(
theme
=>
({
root
:
{},
...
...
@@ -101,8 +101,7 @@ function RawFiles({api, user, data, uploadId, entryId, raiseError}) {
const
[
files
,
setFiles
]
=
useState
(
null
)
const
[
loading
,
setLoading
]
=
useState
(
false
)
const
[
doesNotExist
,
setDoesNotExist
]
=
useState
(
false
)
const
c
=
useContext
(
apiContextV1
)
const
apiv1
=
c
.
api
const
apiv1
=
useApi
()
useEffect
(()
=>
{
setSelectedFiles
([])
...
...
gui/src/components/uploads/UploadsPage.js
0 → 100644
View file @
b1593dd2
/*
* Copyright The NOMAD Authors.
*
* This file is part of NOMAD. See https://nomad-lab.eu for further info.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import
React
from
'
react
'
import
PropTypes
,
{
instanceOf
}
from
'
prop-types
'
import
Markdown
from
'
../Markdown
'
import
{
withStyles
,
Paper
,
IconButton
,
FormGroup
,
FormLabel
,
Tooltip
,
Typography
,
Link
}
from
'
@material-ui/core
'
import
UploadIcon
from
'
@material-ui/icons/CloudUpload
'
import
Dropzone
from
'
react-dropzone
'
import
Upload
from
'
./Upload
'
import
{
compose
}
from
'
recompose
'
import
ReloadIcon
from
'
@material-ui/icons/Cached
'
import
MoreIcon
from
'
@material-ui/icons/MoreHoriz
'
import
ClipboardIcon
from
'
@material-ui/icons/Assignment
'
import
HelpDialog
from
'
../Help
'
import
{
withApi
}
from
'
../api
'
import
{
withCookies
,
Cookies
}
from
'
react-cookie
'
import
Pagination
from
'
material-ui-flat-pagination
'
import
{
CopyToClipboard
}
from
'
react-copy-to-clipboard
'
import
{
guiBase
,
appBase
}
from
'
../../config
'
import
qs
from
'
qs
'
import
{
CodeList
}
from
'
../About
'
export
const
help
=
`
NOMAD allows you to upload data. After upload, NOMAD will process your data: it will
identify the main output files of supported codes.
and then it will parse these files. The result will be a list of entries (one per each identified mainfile).
Each entry is associated with metadata. This is data that NOMAD acquired from your files and that
describe your calculations (e.g. chemical formula, used code, system type and symmetry, etc.).
Furthermore, you can provide your own metadata (comments, references, co-authors, etc.).
At first, uploaded data is only visible to you. Before others can actually see and download
your data, you need to publish your upload.
#### Prepare and upload files
Please put all the relevant files of all the calculations
you want to upload into a single
\`
*.zip
\`
or
\`
*.tar.gz
\`
archive.
We encourage you to add all code input and
output files, as well as any other auxiliary files that you might have created.
You can put data from multiple calculations into one file using as many directories as
you like. NOMAD will consider all files on a single directory to form a single entry.
Ideally, you put only files related to a single code run into each directory. If users
want to download an entry, they can download all files in the respective directory.
The directory structure can be nested.
Drop your archive file(s) on the dropbox. You can also click the dropbox to select the file from
your hard drive. Alternatively, you can upload files via the given shell command.
Replace
\`
<local_file>
\`
with your archive file. After executing the command,
return here and press the reload button below).
There is a limit of 10 unpublished uploads per user. Please accumulate all data into as
few uploads as possible. But, there is a also an upper limit of 32 GB per upload.
Please upload multiple archives, if you have more than 32 GB of data to upload.
#### The staging area
Uploaded data will not be public immediately. Below you will find all your unpublished and
published uploads. The unpublished uploads are only visible to you. You can see the
progress on the processing, you can review your uploads, and publish or delete them again.
Click on an upload to see more details about its contents. Click on processed calculations
to see their metadata, archive data, and a processing log. In the details view, you also
find buttons for editing user metadata, deleting uploads, and publishing uploads. Only
full uploads can be deleted or published.
#### Publishing and embargo
If you press publish, a dialog will appear that allows you to set an
*embargo* or publish your data as *Open Access* right away. The *embargo* allows you to share
data with selected users, create a DOI for your data, and later publish the data.
The *embargo* might last up to 36 month before data becomes public automatically.
During an *embargo* the data (and datasets created from this data) are already visible and
findable, but only you and users you share the data with (i.e. users you added under
*share with* when editing entries) can view and download the raw-data and archive.
#### Processing errors
We distinguish between uploads that fail processing completely and uploads that contain
entries that could not be processed. The former might be caused by issues during the