Commit cbce84c9 authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Add URLs to parsers/codes. Added code list and mini doc to upload page. #343

parent 6f9b20b5
Pipeline #75113 passed with stages
in 22 minutes and 15 seconds
...@@ -9,6 +9,26 @@ import { domains } from './domains' ...@@ -9,6 +9,26 @@ import { domains } from './domains'
import { Grid, Card, CardContent, Typography, makeStyles, Link } from '@material-ui/core' import { Grid, Card, CardContent, Typography, makeStyles, Link } from '@material-ui/core'
import { Link as RouterLink, useHistory } from 'react-router-dom' import { Link as RouterLink, useHistory } from 'react-router-dom'
export const CodeList = () => {
const {info} = useContext(apiContext)
if (!info) {
return '...'
}
return info.codes.reduce((result, code, index) => {
if (index !== 0) {
result.push(', ')
}
if (code.code_homepage) {
result.push(<Link target="external" key={code.code_name} href={code.code_homepage}>{code.code_name}</Link>)
} else {
result.push(code.code_name)
}
return result
}, [])
}
const useCardStyles = makeStyles(theme => ({ const useCardStyles = makeStyles(theme => ({
title: { title: {
marginBottom: theme.spacing(1) marginBottom: theme.spacing(1)
...@@ -173,7 +193,7 @@ export default function About() { ...@@ -173,7 +193,7 @@ export default function About() {
You can inspect the Archive form and extracted metadata before You can inspect the Archive form and extracted metadata before
publishing your data. publishing your data.
</p> </p>
<p>NOMAD supports most community codes: {info ? info.codes.join(', ') : '...'}</p> <p>NOMAD supports most community codes: <CodeList/></p>
<p> <p>
To use NOMAD&apos;s parsers and normalizers outside of NOMAD. To use NOMAD&apos;s parsers and normalizers outside of NOMAD.
Read <Link href="">here</Link> on how to install Read <Link href="">here</Link> on how to install
......
import React from 'react' import React from 'react'
import PropTypes, { instanceOf } from 'prop-types' import PropTypes, { instanceOf } from 'prop-types'
import Markdown from '../Markdown' import Markdown from '../Markdown'
import { withStyles, Paper, IconButton, FormGroup, FormLabel, Tooltip } from '@material-ui/core' import { withStyles, Paper, IconButton, FormGroup, FormLabel, Tooltip, Typography } from '@material-ui/core'
import UploadIcon from '@material-ui/icons/CloudUpload' import UploadIcon from '@material-ui/icons/CloudUpload'
import Dropzone from 'react-dropzone' import Dropzone from 'react-dropzone'
import Upload from './Upload' import Upload from './Upload'
...@@ -16,6 +16,7 @@ import Pagination from 'material-ui-flat-pagination' ...@@ -16,6 +16,7 @@ import Pagination from 'material-ui-flat-pagination'
import { CopyToClipboard } from 'react-copy-to-clipboard' import { CopyToClipboard } from 'react-copy-to-clipboard'
import { guiBase } from '../../config' import { guiBase } from '../../config'
import qs from 'qs' import qs from 'qs'
import { CodeList } from '../About'
export const help = ` export const help = `
NOMAD allows you to upload data. After upload, NOMAD will process your data: it will NOMAD allows you to upload data. After upload, NOMAD will process your data: it will
...@@ -126,7 +127,8 @@ class UploadPage extends React.Component { ...@@ -126,7 +127,8 @@ class UploadPage extends React.Component {
'& svg': { '& svg': {
marginLeft: 'auto', marginLeft: 'auto',
marginRight: 'auto' marginRight: 'auto'
} },
marginTop: theme.spacing(3)
}, },
dropzoneAccept: { dropzoneAccept: {
background: theme.palette.primary.main, background: theme.palette.primary.main,
...@@ -267,6 +269,16 @@ class UploadPage extends React.Component { ...@@ -267,6 +269,16 @@ class UploadPage extends React.Component {
return ( return (
<div className={classes.root}> <div className={classes.root}>
<Typography>
To prepare your data, simply use <b>zip</b> or <b>tar</b> to create a single file that contains
all your files as they are. These .zip/.tar files can contain subdirectories and additional files.
NOMAD will search through all files and identify the relevant files automatically.
Each uploaded file can be <b>up to 32GB</b> in size, you can have <b>up to 10 unpublished
uploads</b> simultaneously. Your uploaded data is not published right away.
</Typography>
<Typography>
The following codes are supported: <CodeList/>.
</Typography>
<Paper className={classes.dropzoneContainer}> <Paper className={classes.dropzoneContainer}>
<Dropzone <Dropzone
accept={[ accept={[
...@@ -288,7 +300,7 @@ class UploadPage extends React.Component { ...@@ -288,7 +300,7 @@ class UploadPage extends React.Component {
rejectClassName={classes.dropzoneReject} rejectClassName={classes.dropzoneReject}
onDrop={this.onDrop.bind(this)} onDrop={this.onDrop.bind(this)}
> >
<p>drop .tar.gz or .zip files here</p> <p>click or drop .tar.gz/.zip files here</p>
<UploadIcon style={{fontSize: 36}}/> <UploadIcon style={{fontSize: 36}}/>
</Dropzone> </Dropzone>
</Paper> </Paper>
......
...@@ -54,10 +54,15 @@ statistics_info_model = api.model('StatisticsInfo', { ...@@ -54,10 +54,15 @@ statistics_info_model = api.model('StatisticsInfo', {
# 'archive_file_size': fields.Integer(description='Total amount of binary archive data in TB') # 'archive_file_size': fields.Integer(description='Total amount of binary archive data in TB')
}) })
code_info_model = api.model('CodeInfo', {
'code_name': fields.String(description='Name of the code or input format', allow_null=True),
'code_homepage': fields.String(description='Homepage of the code or input format', allow_null=True)
}, allow_null=True, skip_none=True)
info_model = api.model('Info', { info_model = api.model('Info', {
'parsers': fields.List(fields.String), 'parsers': fields.List(fields.String),
'metainfo_packages': fields.List(fields.String), 'metainfo_packages': fields.List(fields.String),
'codes': fields.List(fields.String), 'codes': fields.List(fields.Nested(code_info_model)),
'normalizers': fields.List(fields.String), 'normalizers': fields.List(fields.String),
'domains': fields.List(fields.Nested(model=domain_model)), 'domains': fields.List(fields.Nested(model=domain_model)),
'statistics': fields.Nested(model=statistics_info_model, description='General NOMAD statistics'), 'statistics': fields.Nested(model=statistics_info_model, description='General NOMAD statistics'),
...@@ -88,10 +93,14 @@ class InfoResource(Resource): ...@@ -88,10 +93,14 @@ class InfoResource(Resource):
@api.marshal_with(info_model, skip_none=True, code=200, description='Info send') @api.marshal_with(info_model, skip_none=True, code=200, description='Info send')
def get(self): def get(self):
''' Return information about the nomad backend and its configuration. ''' ''' Return information about the nomad backend and its configuration. '''
codes = [ codes_dict = {}
parser.code_name for parser in parsing.parser_dict.values():
for parser in parsing.parser_dict.values() if isinstance(parser, parsing.MatchingParser) and parser.domain == 'dft':
if isinstance(parser, parsing.MatchingParser) and parser.domain == 'dft'] code_name = parser.code_name
if code_name in codes_dict:
continue
codes_dict[code_name] = dict(code_name=code_name, code_homepage=parser.code_homepage)
codes = sorted(list(codes_dict.values()), key=lambda code_info: code_info['code_name'].lower())
return { return {
'parsers': [ 'parsers': [
...@@ -100,7 +109,7 @@ class InfoResource(Resource): ...@@ -100,7 +109,7 @@ class InfoResource(Resource):
'metainfo_packages': ['general', 'general.experimental', 'common', 'public'] + sorted([ 'metainfo_packages': ['general', 'general.experimental', 'common', 'public'] + sorted([
key[key.index('/') + 1:] key[key.index('/') + 1:]
for key in parsing.parser_dict.keys()]), for key in parsing.parser_dict.keys()]),
'codes': sorted(set(codes), key=lambda x: x.lower()), 'codes': codes,
'normalizers': [normalizer.__name__ for normalizer in normalizing.normalizers], 'normalizers': [normalizer.__name__ for normalizer in normalizing.normalizers],
'statistics': statistics(), 'statistics': statistics(),
'domains': [ 'domains': [
......
...@@ -178,7 +178,7 @@ parsers = [ ...@@ -178,7 +178,7 @@ parsers = [
mainfile_name_re=(r'.*/phonopy-FHI-aims-displacement-0*1/control.in$') mainfile_name_re=(r'.*/phonopy-FHI-aims-displacement-0*1/control.in$')
), ),
LegacyParser( LegacyParser(
name='parsers/vasp', code_name='VASP', name='parsers/vasp', code_name='VASP', code_homepage='https://www.vasp.at/',
parser_class_name='vaspparser.VASPRunParser', parser_class_name='vaspparser.VASPRunParser',
mainfile_mime_re=r'(application/.*)|(text/.*)', mainfile_mime_re=r'(application/.*)|(text/.*)',
mainfile_contents_re=( mainfile_contents_re=(
......
...@@ -99,6 +99,8 @@ class MatchingParser(Parser): ...@@ -99,6 +99,8 @@ class MatchingParser(Parser):
A parser implementation that used regular experessions to match mainfiles. A parser implementation that used regular experessions to match mainfiles.
Arguments: Arguments:
code_name: The name of the code or input format
code_homepage: The homepage of the code or input format
mainfile_mime_re: A regexp that is used to match against a files mime type mainfile_mime_re: A regexp that is used to match against a files mime type
mainfile_contents_re: A regexp that is used to match the first 1024 bytes of a mainfile_contents_re: A regexp that is used to match the first 1024 bytes of a
potential mainfile. potential mainfile.
...@@ -107,7 +109,7 @@ class MatchingParser(Parser): ...@@ -107,7 +109,7 @@ class MatchingParser(Parser):
supported_compressions: A list of [gz, bz2], if the parser supports compressed files supported_compressions: A list of [gz, bz2], if the parser supports compressed files
''' '''
def __init__( def __init__(
self, name: str, code_name: str, self, name: str, code_name: str, code_homepage: str = None,
mainfile_contents_re: str = None, mainfile_contents_re: str = None,
mainfile_binary_header: bytes = None, mainfile_binary_header: bytes = None,
mainfile_mime_re: str = r'text/.*', mainfile_mime_re: str = r'text/.*',
...@@ -118,6 +120,7 @@ class MatchingParser(Parser): ...@@ -118,6 +120,7 @@ class MatchingParser(Parser):
super().__init__() super().__init__()
self.name = name self.name = name
self.code_name = code_name self.code_name = code_name
self.code_homepage = code_homepage
self.domain = domain self.domain = domain
self._mainfile_binary_header = mainfile_binary_header self._mainfile_binary_header = mainfile_binary_header
self._mainfile_mime_re = re.compile(mainfile_mime_re) self._mainfile_mime_re = re.compile(mainfile_mime_re)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment