Commit 8800cdc6 authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Enabled domain awareness for metainfo browser.

parent 7268932c
Pipeline #47291 passed with stages
in 16 minutes and 52 seconds
Subproject commit 418ea7a2fae3c5726e970f52574916955ffe2fe4
Subproject commit 6360fef5c9abe8ba97ce611c8ad3ac87c7363378
......@@ -30,7 +30,8 @@ const drawerWidth = 200
const toolbarTitles = {
'/': 'About nomad@FAIRDI',
'/search': 'Search',
'/uploads': 'Upload Your Own Data'
'/uploads': 'Upload Your Own Data',
'/metainfo': 'The Nomad Meta Info'
}
const toolbarThemes = {
......
......@@ -17,8 +17,8 @@ class Schema {
isValue = (element) => element.mType === this.value
isProperty = (element) => this.isValue(element) || this.isReference(element)
isDefinition = (element) => this.isCategory(element) || this.isFeature(element)
isPakage = (element) => element.mType === this.pkg
isElement = (element) => this.isPakage(element) || this.isDefinition(element)
isPackage = (element) => element.mType === this.pkg
isElement = (element) => this.isPackage(element) || this.isDefinition(element)
type = (type) => {
if (type === 'C') {
......@@ -44,7 +44,7 @@ class Schema {
}
allContents = (element, func) => {
if (this.isPakage(element)) {
if (this.isPackage(element)) {
(element.definitions || []).forEach(element => this.allContents(element, func))
}
func(element)
......@@ -162,7 +162,7 @@ export default class MetaInfoRepository {
definition.parent.features = definition.parent.features || []
definition.parent.features.push(definition)
}
if (schema.isPakage(definition)) {
if (schema.isPackage(definition)) {
definition.definitions.forEach(feature => {
feature.package = definition
})
......@@ -195,8 +195,10 @@ export default class MetaInfoRepository {
const {name} = namedElement
if (this.names[name]) {
this.errors.push(new BadNomadMIError(`Element with name ${namedElement.name} does already exist.`))
return false
} else {
this.names[name] = namedElement
return true
}
}
......@@ -219,6 +221,9 @@ export default class MetaInfoRepository {
_superNames: superNames.map(ref => this.createProxy(ref))
}
// normalisation
definition.miJson.shape = definition.miJson.shape || []
if (isSection) {
definition.mType = schema.section
} else if (isCategory) {
......@@ -238,8 +243,11 @@ export default class MetaInfoRepository {
this.errors.push(new BadNomadMIError(`Cannot determine mType ${metaInfo.kindStr} of feature ${name}:${metaInfo.name}`))
}
this.addName(definition)
return definition
if (this.addName(definition)) {
return definition
} else {
return null
}
}
const metaInfos = json.metaInfos || []
......@@ -247,7 +255,7 @@ export default class MetaInfoRepository {
mType: schema.pkg,
name: name,
description: json.description,
definitions: metaInfos.map(transformMetaInfo)
definitions: metaInfos.map(transformMetaInfo).filter(definition => definition !== null)
}
this.addName(pkg)
......
......@@ -3,12 +3,12 @@ import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import Viewer from './Viewer'
import PropTypes from 'prop-types'
import { link } from 'fs'
import { withApi } from '../api'
import { Help } from '../help'
import MetainfoSearch from './MetainfoSearch'
import { FormControl, withStyles, Select, Input, MenuItem, ListItemText, InputLabel, FormGroup } from '@material-ui/core'
import { FormControl, withStyles, Select, Input, MenuItem, ListItemText, InputLabel } from '@material-ui/core'
import { compose } from 'recompose'
import { schema } from '../MetaInfoRepository'
const ITEM_HEIGHT = 48
const ITEM_PADDING_TOP = 8
......@@ -45,6 +45,7 @@ class MetaInfoBrowser extends Component {
})
initialState = {
domainRootSection: null,
metainfos: null,
allMetainfos: null,
selectedPackage: null,
......@@ -60,25 +61,36 @@ class MetaInfoBrowser extends Component {
}
update(pkg) {
this.props.api.getMetaInfo(pkg).then(metainfos => {
const metainfoName = this.props.metainfo || 'section_run'
const definition = metainfos.get(metainfoName)
if (!definition) {
this.props.history.push('/metainfo/section_run')
} else {
this.setState({loadedPackage: pkg, metainfos: metainfos})
}
this.props.api.getInfo().then(info => {
this.props.api.getMetaInfo(pkg || info.domain.metainfo.all_package).then(metainfos => {
const metainfoName = this.props.metainfo || info.domain.metainfo.root_sections[0]
const definition = metainfos.get(metainfoName)
if (!definition) {
this.props.history.push(`/metainfo/${info.domain.metainfo.root_sections[0]}`)
} else {
this.setState({loadedPackage: pkg, metainfos: metainfos})
}
}).catch(error => {
this.props.raiseError(error)
})
}).catch(error => {
this.props.raiseError(error)
})
}
init() {
this.props.api.getMetaInfo('all.nomadmetainfo.json').then(metainfos => {
const metainfoName = this.props.metainfo || 'section_run'
const definition = metainfos.get(metainfoName)
this.setState({allMetainfos: metainfos, selectedPackage: definition.package.name})
this.update(definition.package.name)
this.props.api.getInfo().then(info => {
this.props.api.getMetaInfo(info.domain.metainfo.all_package).then(metainfos => {
const metainfoName = this.props.metainfo || info.domain.metainfo.root_sections[0]
const definition = metainfos.get(metainfoName)
this.setState({
domainRootSection: info.domain.metainfo.root_sections[0],
allMetainfos: metainfos,
selectedPackage: definition.package.name})
this.update(definition.package.name)
}).catch(error => {
this.props.raiseError(error)
})
}).catch(error => {
this.props.raiseError(error)
})
......@@ -108,13 +120,13 @@ class MetaInfoBrowser extends Component {
render() {
const { classes, loading } = this.props
const { metainfos, selectedPackage, allMetainfos, loadedPackage } = this.state
const { metainfos, selectedPackage, allMetainfos, loadedPackage, domainRootSection } = this.state
if (!metainfos || !allMetainfos) {
return <div />
}
const metainfoName = this.props.metainfo || 'section_run'
const metainfoName = this.props.metainfo || domainRootSection || 'section_run'
const metainfo = metainfos.resolve(metainfos.createProxy(metainfoName))
return <div>
......@@ -168,7 +180,7 @@ class MetaInfoBrowser extends Component {
</Select>
</FormControl>
<MetainfoSearch classes={{root: classes.search}}
suggestions={Object.values(metainfos.names)}
suggestions={Object.values(metainfos.names).filter(metainfo => !schema.isPackage(metainfo))}
onChange={this.handleSearch}
/>
</form>
......
......@@ -57,15 +57,17 @@ class SearchPage extends React.Component {
searchResults: {}
})
state = {
data: {
results: [],
pagination: {
total: 0
},
aggregations: {},
metrics: {}
static emptySearchData = {
results: [],
pagination: {
total: 0
},
aggregations: {},
metrics: {}
}
state = {
data: SearchPage.emptySearchData,
owner: 'all',
searchState: {
...SearchAggregations.defaultState
......@@ -111,10 +113,10 @@ class SearchPage extends React.Component {
...searchStateRest
}).then(data => {
this.setState({
data: data
data: data || SearchPage.emptySearchData
})
}).catch(errors => {
this.setState({data: [], total: 0, owner: owner})
this.setState({data: SearchPage.emptySearchData, owner: owner})
this.props.raiseError(errors)
})
}
......
......@@ -124,7 +124,14 @@ class MetainfoResource(Resource):
try:
return load_metainfo(metainfo_package_name), 200
except FileNotFoundError:
abort(404, message='The metainfo %s does not exist.' % metainfo_package_name)
parser_prefix = metainfo_package_name[:-len('.nomadmetainfo.json')]
alternative_path = os.path.join(
metainfo_main_path,
'../../../parsers/{0}/{0}parser/{0}.nomadmetainfo.json'.format(parser_prefix))
try:
return load_metainfo(alternative_path, is_path=True), 200
except FileNotFoundError:
abort(404, message='The metainfo %s does not exist.' % metainfo_package_name)
metainfo_main_path = os.path.dirname(os.path.abspath(nomad_meta_info.__file__))
......
......@@ -32,11 +32,17 @@ domain_quantity_model = api.model('DomainQuantity', {
'order_default': fields.Boolean
})
metainfo_model = api.model('Metainfo', {
'all_package': fields.String(description='Name of the metainfo package that references all available packages, i.e. the complete metainfo.'),
'root_sections': fields.List(fields.String, description='Name of the topmost section, e.g. section_run for computational material science data.')
})
domain_model = api.model('Domain', {
'name': fields.String,
'quantities': fields.List(fields.Nested(model=domain_quantity_model)),
'aggregations_names': fields.List(fields.String),
'metrics_names': fields.List(fields.String)
'metrics_names': fields.List(fields.String),
'metainfo': fields.Nested(model=metainfo_model)
})
git_info_model = api.model('GitInfo', {
......@@ -68,7 +74,11 @@ class InfoResource(Resource):
'name': datamodel.Domain.instance.name,
'quantities': [quantity for quantity in datamodel.Domain.instance.quantities.values()],
'metrics_names': datamodel.Domain.instance.metrics_names,
'aggregations_names': datamodel.Domain.instance.aggregations_names
'aggregations_names': datamodel.Domain.instance.aggregations_names,
'metainfo': {
'all_package': datamodel.Domain.instance.metainfo_all_package,
'root_sections': datamodel.Domain.instance.root_sections
}
},
'version': config.version,
'release': config.release,
......
......@@ -21,7 +21,8 @@ from bravado.requests_client import RequestsClient
from bravado.client import SwaggerClient
from urllib.parse import urlparse
from nomad import config, utils, infrastructure
from nomad import config as nomad_config
from nomad import utils, infrastructure
def create_client():
......@@ -32,15 +33,15 @@ def _create_client(*args, **kwargs):
return __create_client(*args, **kwargs)
def __create_client(user: str = config.client.user, password: str = config.client.password):
def __create_client(user: str = nomad_config.client.user, password: str = nomad_config.client.password):
""" A factory method to create the client. """
host = urlparse(config.client.url).netloc.split(':')[0]
host = urlparse(nomad_config.client.url).netloc.split(':')[0]
http_client = RequestsClient()
if user is not None:
http_client.set_basic_auth(host, user, password)
client = SwaggerClient.from_url(
'%s/swagger.json' % config.client.url,
'%s/swagger.json' % nomad_config.client.url,
http_client=http_client)
utils.get_logger(__name__).info('created bravado client', user=user)
......@@ -55,26 +56,30 @@ def handle_common_errors(func):
except requests.exceptions.ConnectionError:
click.echo(
'\nCould not connect to nomad at %s. '
'Check connection and url.' % config.client.url)
'Check connection and url.' % nomad_config.client.url)
sys.exit(0)
return wrapper
@click.group()
@click.option('-n', '--url', default=config.client.url, help='The URL where nomad is running, default is "%s".' % config.client.url)
@click.option('-u', '--user', default=None, help='the user name to login, default is "%s" login.' % config.client.user)
@click.option('-w', '--password', default=config.client.password, help='the password used to login.')
@click.option('-n', '--url', default=nomad_config.client.url, help='The URL where nomad is running, default is "%s".' % nomad_config.client.url)
@click.option('-u', '--user', default=None, help='the user name to login, default is "%s" login.' % nomad_config.client.user)
@click.option('-w', '--password', default=nomad_config.client.password, help='the password used to login.')
@click.option('-v', '--verbose', help='sets log level to info', is_flag=True)
@click.option('--debug', help='sets log level to debug', is_flag=True)
def cli(url: str, verbose: bool, debug: bool, user: str, password: str):
@click.option('--config', help='the config file to use')
def cli(url: str, verbose: bool, debug: bool, user: str, password: str, config: str):
if config is not None:
nomad_config.load_config(config_file=config)
if debug:
config.console_log_level = logging.DEBUG
nomad_config.console_log_level = logging.DEBUG
elif verbose:
config.console_log_level = logging.INFO
nomad_config.console_log_level = logging.INFO
else:
config.console_log_level = logging.WARNING
nomad_config.console_log_level = logging.WARNING
config.service = os.environ.get('NOMAD_SERVICE', 'client')
nomad_config.service = os.environ.get('NOMAD_SERVICE', 'client')
infrastructure.setup_logging()
logger = utils.get_logger(__name__)
......@@ -82,7 +87,7 @@ def cli(url: str, verbose: bool, debug: bool, user: str, password: str):
logger.info('Used nomad is %s' % url)
logger.info('Used user is %s' % user)
config.client.url = url
nomad_config.client.url = url
global _create_client
......
......@@ -210,13 +210,17 @@ class Domain:
domain specific quantities.
quantities: Additional specifications for the quantities in ``domain_entry_class`` as
instances of :class:`DomainQuantity`.
root_sections: The name of the possible root sections for this domain.
metainfo_all_package: The name of the full metainfo package for this domain.
"""
instance: 'Domain' = None
instances: Dict[str, 'Domain'] = {}
def __init__(
self, name: str, domain_entry_class: Type[CalcWithMetadata],
quantities: Dict[str, DomainQuantity], root_sections=['section_run', 'section_entry_info']) -> None:
quantities: Dict[str, DomainQuantity],
root_sections=['section_run', 'section_entry_info'],
metainfo_all_package='all.nomadmetainfo.json') -> None:
if name == config.domain:
assert Domain.instance is None, 'you can only define one domain.'
Domain.instance = self
......@@ -227,6 +231,7 @@ class Domain:
self.domain_entry_class = domain_entry_class
self.quantities: Dict[str, DomainQuantity] = {}
self.root_sections = root_sections
self.metainfo_all_package = metainfo_all_package
reference_domain_calc = domain_entry_class()
reference_general_calc = CalcWithMetadata()
......
......@@ -99,6 +99,7 @@ class EMSEntryWithMetadata(CalcWithMetadata):
Domain(
'EMS', EMSEntryWithMetadata,
root_sections=['section_experiment', 'section_entry_info'],
metainfo_all_package='all.experimental.nomadmetainfo.json',
quantities=dict(
formula=DomainQuantity(
'The chemical (hill) formula of the simulated system.',
......
......@@ -368,7 +368,7 @@ parsers = [
)
]
""" Instanciation and constructor based config of all parsers. """
""" Instantiation and constructor based config of all parsers. """
parser_dict = {parser.name: parser for parser in parsers} # type: ignore
""" A dict to access parsers by name. Usually 'parsers/<...>', e.g. 'parsers/vasp'. """
Supports Markdown
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