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
a420d4bc
Commit
a420d4bc
authored
May 02, 2020
by
Markus Scheidgen
Browse files
Fixed optimade in repo search. Added optimade to search bar.
#327
parent
0c926116
Pipeline
#74214
failed with stages
in 37 minutes and 5 seconds
Changes
6
Pipelines
1
Show whitespace changes
Inline
Side-by-side
gui/src/components/api.js
View file @
a420d4bc
...
...
@@ -125,7 +125,7 @@ function handleApiError(e) {
let
error
=
null
if
(
e
.
response
)
{
const
body
=
e
.
response
.
body
const
message
=
(
body
&&
body
.
m
es
sage
)
?
body
.
message
:
e
.
response
.
statusText
const
message
=
(
body
&&
(
body
.
d
es
cription
||
body
.
message
))
||
e
.
response
.
statusText
const
errorMessage
=
`
${
message
}
(
${
e
.
response
.
status
}
)`
if
(
e
.
response
.
status
===
404
)
{
error
=
new
DoesNotExist
(
errorMessage
)
...
...
@@ -136,7 +136,9 @@ function handleApiError(e) {
}
else
{
error
=
new
Error
(
errorMessage
)
}
console
.
log
(
'
### D
'
,
message
,
body
)
error
.
status
=
e
.
response
.
status
error
.
apiMessage
=
message
}
else
{
if
(
e
.
message
===
'
Failed to fetch
'
)
{
error
=
new
ApiError
(
e
.
message
)
...
...
gui/src/components/search/SearchBar.js
View file @
a420d4bc
...
...
@@ -2,7 +2,7 @@ import React, { useRef, useState, useContext, useCallback, useMemo } from 'react
import
{
searchContext
}
from
'
./SearchContext
'
import
Autocomplete
from
'
@material-ui/lab/Autocomplete
'
import
TextField
from
'
@material-ui/core/TextField
'
import
{
CircularProgress
}
from
'
@material-ui/core
'
import
{
CircularProgress
,
InputAdornment
,
Typography
,
Button
,
Tooltip
}
from
'
@material-ui/core
'
import
*
as
searchQuantities
from
'
../../searchQuantities.json
'
import
{
apiContext
}
from
'
../api
'
...
...
@@ -26,7 +26,7 @@ const Options = {
*/
export
default
function
SearchBar
()
{
const
suggestionsTimerRef
=
useRef
(
null
)
const
{
response
:
{
statistics
,
pagination
},
domain
,
query
,
apiQuery
,
setQuery
}
=
useContext
(
searchContext
)
const
{
response
:
{
statistics
,
pagination
,
error
},
domain
,
query
,
apiQuery
,
setQuery
}
=
useContext
(
searchContext
)
const
defaultOptions
=
useMemo
(()
=>
{
return
Object
.
keys
(
searchQuantities
)
.
map
(
quantity
=>
searchQuantities
[
quantity
].
name
)
...
...
@@ -37,13 +37,30 @@ export default function SearchBar() {
const
[
options
,
setOptions
]
=
useState
(
defaultOptions
)
const
[
loading
,
setLoading
]
=
useState
(
false
)
const
[
inputValue
,
setInputValue
]
=
useState
(
''
)
const
[
searchType
,
setSearchType
]
=
useState
(
'
nomad
'
)
const
{
api
}
=
useContext
(
apiContext
)
const
autocompleteValue
=
Object
.
keys
(
query
).
map
(
quantity
=>
Options
.
join
(
quantity
,
query
[
quantity
]))
const
handleSearchTypeClicked
=
useCallback
(()
=>
{
if
(
searchType
===
'
nomad
'
)
{
setSearchType
(
'
optimade
'
)
// handleChange(null, [])
}
else
{
setSearchType
(
'
nomad
'
)
// handleChange(null, [])
}
},
[
searchType
,
setSearchType
])
const
handleOptimadeEntered
=
useCallback
(
query
=>
{
setQuery
({
'
dft.optimade
'
:
query
})
})
let
helperText
=
''
if
(
pagination
&&
statistics
)
{
if
(
error
)
{
helperText
=
''
+
(
error
.
apiMessage
||
error
)
}
else
if
(
pagination
&&
statistics
)
{
if
(
pagination
.
total
===
0
)
{
helperText
=
<
span
>
There
are
no
more
entries
matching
your
criteria
.
<
/span
>
}
else
{
...
...
@@ -92,7 +109,7 @@ export default function SearchBar() {
setLoading
(
false
)
})
},
200
)
},
[
api
,
suggestionsTimerRef
])
},
[
api
,
suggestionsTimerRef
,
apiQuery
])
const
handleInputChange
=
useCallback
((
event
,
value
,
reason
)
=>
{
if
(
reason
===
'
input
'
)
{
...
...
@@ -147,6 +164,29 @@ export default function SearchBar() {
}
},
[
open
])
const
commonTextFieldProps
=
params
=>
({
error
:
!!
error
,
helperText
:
helperText
,
variant
:
'
outlined
'
,
fullWidth
:
true
,
...
params
})
const
commonInputProps
=
(
params
)
=>
({
...
params
,
startAdornment
:
(
<
React
.
Fragment
>
<
InputAdornment
position
=
"
start
"
>
<
Tooltip
title
=
"
Switch between NOMAD's quantity=value search and the Optimade filter language.
"
>
<
Button
onClick
=
{
handleSearchTypeClicked
}
size
=
"
small
"
>
{
searchType
}
<
/Button
>
<
/Tooltip
>
<
/InputAdornment
>
{
params
.
startAdornment
}
<
/React.Fragment
>
)
})
if
(
searchType
===
'
nomad
'
)
{
return
<
Autocomplete
multiple
freeSolo
...
...
@@ -169,12 +209,10 @@ export default function SearchBar() {
filterOptions
=
{
filterOptions
}
renderInput
=
{(
params
)
=>
(
<
TextField
{...
params
}
helperText
=
{
helperText
}
label
=
'
Search with quantity=value
'
variant
=
'
outlined
'
{...
commonTextFieldProps
(
params
)}
label
=
{
searchType
===
'
nomad
'
?
'
Search with quantity=value
'
:
'
Search with Optimade filter language
'
}
InputProps
=
{{
...
params
.
InputProps
,
...
commonInputProps
(
params
.
InputProps
)
,
endAdornment
:
(
<
React
.
Fragment
>
{
loading
?
<
CircularProgress
color
=
'
inherit
'
size
=
{
20
}
/> : null
}
...
...
@@ -185,4 +223,21 @@ export default function SearchBar() {
/
>
)}
/
>
}
else
{
return
<
TextField
{...
commonTextFieldProps
({})}
label
=
{
searchType
===
'
nomad
'
?
'
Search with quantity=value
'
:
'
Search with Optimade filter language
'
}
InputProps
=
{{
...
commonInputProps
({})
}}
defaultValue
=
{
query
[
'
dft.optimade
'
]
||
''
}
onKeyPress
=
{(
ev
)
=>
{
console
.
log
(
`Pressed keyCode
${
ev
.
key
}
`
)
if
(
ev
.
key
===
'
Enter
'
)
{
handleOptimadeEntered
(
ev
.
target
.
value
)
ev
.
preventDefault
()
}
}}
/
>
}
}
gui/src/components/search/SearchContext.js
View file @
a420d4bc
...
...
@@ -27,6 +27,7 @@ export const Dates = {
searchQuantities
[
'
from_time
'
]
=
{
name
:
'
from_time
'
}
searchQuantities
[
'
until_time
'
]
=
{
name
:
'
until_time
'
}
searchQuantities
[
'
dft.optimade
'
]
=
{
name
:
'
dft.optimade
'
}
/**
* A custom hook that reads and writes search parameters from the current URL.
*/
...
...
@@ -144,12 +145,13 @@ export default function SearchContext({initialRequest, initialQuery, query, chil
metrics
:
(
metric
===
domain
.
defaultSearchMetric
)
?
[]
:
[
metric
],
domain
:
domain
.
key
}
console
.
log
(
'
+++
'
,
requestRef
.
current
.
query
)
const
apiQuery
=
{
...
apiRequest
,
owner
:
owner
,
...
initialQuery
,
...
requestRef
.
current
.
query
,
...
query
query
}
if
(
dateHistogram
)
{
dateHistogramInterval
=
Dates
.
intervalSeconds
(
...
...
@@ -169,8 +171,11 @@ export default function SearchContext({initialRequest, initialQuery, query, chil
until_time
:
apiQuery
.
until_time
})
}).
catch
(
error
=>
{
setResponse
({...
emptyResponse
,
metric
:
metric
})
setResponse
({...
emptyResponse
,
metric
:
metric
,
error
:
error
})
console
.
log
(
'
***
'
,
error
,
error
.
status
)
if
(
error
.
status
!==
400
)
{
raiseError
(
error
)
}
})
},
[
requestRef
,
setResponse
,
api
])
...
...
gui/src/config.js
View file @
a420d4bc
...
...
@@ -2,8 +2,8 @@ import { createMuiTheme } from '@material-ui/core'
window
.
nomadEnv
=
window
.
nomadEnv
||
{}
export
const
appBase
=
window
.
nomadEnv
.
appBase
.
replace
(
/
\/
$/
,
''
)
export
const
apiBase
=
'
http://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/testing-major/api
'
//
export const apiBase = `${appBase}/api`
//
export const apiBase = 'http://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/testing-major/api'
export
const
apiBase
=
`
${
appBase
}
/api`
export
const
optimadeBase
=
`
${
appBase
}
/optimade`
export
const
guiBase
=
process
.
env
.
PUBLIC_URL
export
const
matomoUrl
=
window
.
nomadEnv
.
matomoUrl
...
...
nomad/app/api/common.py
View file @
a420d4bc
...
...
@@ -192,8 +192,8 @@ def apply_search_parameters(search_request: search.SearchRequest, args: Dict[str
if
optimade
is
not
None
:
q
=
filterparser
.
parse_filter
(
optimade
)
search_request
.
query
(
q
)
except
filterparser
.
FilterException
:
abort
(
400
,
'
c
ould not parse optimade query
'
)
except
filterparser
.
FilterException
as
e
:
abort
(
400
,
'
C
ould not parse optimade query
: %s'
%
(
str
(
e
))
)
# search parameter
search_request
.
search_parameters
(
**
{
...
...
nomad/app/optimade/filterparser.py
View file @
a420d4bc
...
...
@@ -18,30 +18,15 @@ from elasticsearch_dsl import Q
from
optimade.filterparser
import
LarkParser
from
optimade.filtertransformers.elasticsearch
import
Transformer
,
Quantity
from
nomad.datamodel
import
OptimadeEntry
class
FilterException
(
Exception
):
''' Raised on parsing a filter expression with syntactic of semantic errors. '''
pass
quantities
:
Dict
[
str
,
Quantity
]
=
{
q
.
name
:
Quantity
(
q
.
name
,
es_field
=
'dft.optimade.%s'
%
q
.
name
,
elastic_mapping_type
=
q
.
a_search
.
mapping
.
__class__
)
for
q
in
OptimadeEntry
.
m_def
.
all_quantities
.
values
()
if
'search'
in
q
.
m_annotations
}
quantities
[
'elements'
].
length_quantity
=
quantities
[
'nelements'
]
quantities
[
'dimension_types'
].
length_quantity
=
quantities
[
'dimension_types'
]
quantities
[
'elements'
].
has_only_quantity
=
Quantity
(
name
=
'only_atoms'
)
quantities
[
'elements'
].
nested_quantity
=
quantities
[
'elements_ratios'
]
quantities
[
'elements_ratios'
].
nested_quantity
=
quantities
[
'elements_ratios'
]
_quantities
:
Dict
[
str
,
Quantity
]
=
None
_parser
=
LarkParser
(
version
=
(
0
,
10
,
0
))
_transformer
=
Transformer
(
quantities
=
quantities
.
values
())
_transformer
=
None
def
parse_filter
(
filter_str
:
str
)
->
Q
:
...
...
@@ -54,6 +39,25 @@ def parse_filter(filter_str: str) -> Q:
FilterException: If the given str cannot be parsed, or if there are any semantic
errors in the given expression.
'''
global
_quantities
global
_transformer
if
_quantities
is
None
:
from
nomad.datamodel
import
OptimadeEntry
_quantities
=
{
q
.
name
:
Quantity
(
q
.
name
,
es_field
=
'dft.optimade.%s'
%
q
.
name
,
elastic_mapping_type
=
q
.
a_search
.
mapping
.
__class__
)
for
q
in
OptimadeEntry
.
m_def
.
all_quantities
.
values
()
if
'search'
in
q
.
m_annotations
}
_quantities
[
'elements'
].
length_quantity
=
_quantities
[
'nelements'
]
_quantities
[
'dimension_types'
].
length_quantity
=
_quantities
[
'dimension_types'
]
_quantities
[
'elements'
].
has_only_quantity
=
Quantity
(
name
=
'only_atoms'
)
_quantities
[
'elements'
].
nested_quantity
=
_quantities
[
'elements_ratios'
]
_quantities
[
'elements_ratios'
].
nested_quantity
=
_quantities
[
'elements_ratios'
]
_transformer
=
Transformer
(
quantities
=
_quantities
.
values
())
try
:
parse_tree
=
_parser
.
parse
(
filter_str
)
...
...
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