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

Added search order. Added sorting and opening calc dialog in GUI.

parent 82b03b19
Pipeline #43934 passed with stages
in 22 minutes and 27 seconds
......@@ -8,13 +8,14 @@ import TablePagination from '@material-ui/core/TablePagination'
import TableRow from '@material-ui/core/TableRow'
import Paper from '@material-ui/core/Paper'
import { TableHead, LinearProgress, FormControl, FormControlLabel, Checkbox, FormGroup,
FormLabel, IconButton, MuiThemeProvider, Typography } from '@material-ui/core'
FormLabel, IconButton, MuiThemeProvider, Typography, Tooltip, TableSortLabel } from '@material-ui/core'
import { compose } from 'recompose'
import { withErrors } from './errors'
import AnalyticsIcon from '@material-ui/icons/Settings'
import { analyticsTheme } from '../config'
import Link from 'react-router-dom/Link'
import { withApi } from './api'
import CalcDialog from './CalcDialog'
// import PeriodicTable from './PeriodicTable'
class Repo extends React.Component {
......@@ -45,6 +46,9 @@ class Repo extends React.Component {
},
selectLabel: {
padding: theme.spacing.unit * 2
},
clickableRow: {
cursor: 'pointer'
}
})
......@@ -64,13 +68,24 @@ class Repo extends React.Component {
rowsPerPage: 10,
total: 0,
loading: true,
owner: 'all'
owner: 'all',
sortedBy: 'formula',
sortOrder: 'asc',
openCalc: null
}
update(page, rowsPerPage, owner) {
this.setState({loading: true})
owner = owner || this.state.owner
this.props.api.repoAll(page, rowsPerPage, owner).then(data => {
update(changes) {
changes = changes || {}
const { page, rowsPerPage, owner, sortedBy, sortOrder } = {...this.state, ...changes}
this.setState({loading: true, ...changes})
this.props.api.search({
page: page,
per_page: rowsPerPage,
owner: owner || 'all',
order_by: sortedBy,
order: (sortOrder === 'asc') ? 1 : -1
}).then(data => {
const { pagination: { total, page, per_page }, results } = data
this.setState({
data: results,
......@@ -88,26 +103,41 @@ class Repo extends React.Component {
}
componentDidMount() {
const { page, rowsPerPage } = this.state
this.update(page, rowsPerPage)
this.update()
}
handleChangePage = (event, page) => {
this.update(page + 1, this.state.rowsPerPage)
this.update({page: this.state.page + 1})
}
handleChangeRowsPerPage = event => {
const rowsPerPage = event.target.value
this.update(this.state.page, rowsPerPage)
this.update({rowsPerPage: rowsPerPage})
}
handleOwnerChange(owner) {
this.update(this.state.page, this.state.rowsPerPage, owner)
this.update({owner: owner})
}
handleSort(columnKey) {
if (this.state.sortedBy === columnKey) {
this.update({sortOrder: (this.state.sortOrder === 'asc') ? 'desc' : 'asc'})
} else {
this.update({sortOrder: 'asc', sortedBy: columnKey})
}
}
handleCalcClose() {
this.setState({openCalc: null})
}
handleClickCalc(calc_id) {
this.setState({openCalc: calc_id})
}
render() {
const { classes } = this.props
const { data, rowsPerPage, page, total, loading } = this.state
const { data, rowsPerPage, page, total, loading, sortedBy, sortOrder, openCalc } = this.state
const emptyRows = rowsPerPage - Math.min(rowsPerPage, total - (page - 1) * rowsPerPage)
const ownerLabel = {
......@@ -117,6 +147,7 @@ class Repo extends React.Component {
}
return (
<div className={classes.root}>
{ openCalc ? <CalcDialog calcId={openCalc.calc_id} uploadId={openCalc.upload_id} onClose={() => this.handleCalcClose()} /> : ''}
<Typography variant="h4" className={classes.title}>The Repository Raw Code Data</Typography>
{/* <PeriodicTable/> */}
<FormControl>
......@@ -152,21 +183,33 @@ class Repo extends React.Component {
<Table>
<TableHead>
<TableRow>
{Object.values(Repo.rowConfig).map((name, index) => (
<TableCell padding="dense" key={index}>{name}</TableCell>
{Object.keys(Repo.rowConfig).map(key => (
<TableCell padding="dense" key={key}>
<Tooltip
title="Sort"
placement={'bottom-start'}
enterDelay={300}
>
<TableSortLabel
active={sortedBy === key}
direction={sortOrder}
onClick={() => this.handleSort(key)}
>
{Repo.rowConfig[key]}
</TableSortLabel>
</Tooltip>
</TableCell>
))}
<TableCell/>
</TableRow>
</TableHead>
<TableBody>
{data.map((calc, index) => (
<TableRow hover tabIndex={-1} key={index}>
<TableRow hover tabIndex={-1} key={index} className={classes.clickableRow}>
{Object.keys(Repo.rowConfig).map((key, rowIndex) => (
<TableCell padding="dense" key={rowIndex}>{calc[key]}</TableCell>
<TableCell padding="dense" key={rowIndex} onClick={() => this.handleClickCalc(calc)} >
{calc[key]}
</TableCell>
))}
<TableCell padding="dense">
{/* <CalcLinks uploadId={calc.upload_id} calcId={calc.calc_id} /> */}
</TableCell>
</TableRow>
))}
{emptyRows > 0 && (
......
......@@ -197,13 +197,9 @@ class Api {
.then(response => response.body)
}
async repoAll(page, perPage, owner) {
async search(search) {
const client = await this.swaggerPromise
return client.apis.repo.search({
page: page,
per_page: perPage,
owner: owner || 'all'
})
return client.apis.repo.search(search)
.catch(this.handleApiError)
.then(response => response.body)
}
......
......@@ -97,9 +97,16 @@ class RepoCalcsResource(Resource):
that have the certain value. You can also use these aggregations on an empty
search to determine the possible values.
"""
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 10))
try:
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 10))
order = int(request.args.get('order', -1))
except Exception:
abort(400, message='bad parameter types')
owner = request.args.get('owner', 'all')
order_by = request.args.get('order_by', 'formula')
try:
assert page >= 1
......@@ -107,6 +114,9 @@ class RepoCalcsResource(Resource):
except AssertionError:
abort(400, message='invalid pagination')
if order not in [-1, 1]:
abort(400, message='invalid pagination')
if owner == 'all':
if g.user is None:
q = Q('term', published=True)
......@@ -126,12 +136,10 @@ class RepoCalcsResource(Resource):
data = dict(**request.args)
data.pop('owner', None)
data.pop('page', None)
data.pop('per_page', None)
data.update(per_page=per_page, page=page, order=order, order_by=order_by)
try:
total, results, aggregations = search.aggregate_search(
page=page, per_page=per_page, q=q, **data)
total, results, aggregations = search.aggregate_search(q=q, **data)
except KeyError as e:
abort(400, str(e))
......
......@@ -195,6 +195,9 @@ aggregations = {
search_quantities = {
'formula': ('term', 'formula', 'The full reduced formula.'),
'spacegroup': ('term', 'spacegroup', 'The spacegroup as int.'),
'basis_set': ('term', 'basis_set', 'The basis set type.'),
'atoms': ('term', 'atoms', (
'Search the given atom. This quantity can be used multiple times to search for '
'results with all the given atoms. The atoms are given by their case sensitive '
......@@ -221,7 +224,8 @@ elastic field and description.
def aggregate_search(
page: int = 1, per_page: int = 10, q: Q = None, **kwargs) -> Tuple[int, List[dict], Dict[str, Dict[str, int]]]:
page: int = 1, per_page: int = 10, order_by: str = 'formula', order: int = -1,
q: Q = None, **kwargs) -> Tuple[int, List[dict], Dict[str, Dict[str, int]]]:
"""
Performs a search and returns paginated search results and aggregation bucket sizes
based on key quantities.
......@@ -259,6 +263,10 @@ def aggregate_search(
else:
search.aggs.bucket(aggregation, A('terms', field=aggregation, size=size))
if order_by not in search_quantities:
raise KeyError('Unknown order quantity %s' % order_by)
search = search.sort(order_by if order == 1 else '-%s' % order_by)
response = search[(page - 1) * per_page: page * per_page].execute() # pylint: disable=no-member
total_results = response.hits.total
......
......@@ -545,7 +545,7 @@ class TestRepo(UploadFilesBasedTests):
search.Entry.from_calc_with_metadata(calc_with_metadata).save(refresh=True)
calc_with_metadata.update(calc_id='2', uploader=other_test_user.to_popo(), published=True)
calc_with_metadata.update(atoms=['Fe'], comment='this is a specific word')
calc_with_metadata.update(atoms=['Fe'], comment='this is a specific word', formula='AAA', basis_set='zzz')
search.Entry.from_calc_with_metadata(calc_with_metadata).save(refresh=True)
calc_with_metadata.update(calc_id='3', uploader=other_test_user.to_popo(), published=False)
......@@ -628,9 +628,20 @@ class TestRepo(UploadFilesBasedTests):
results = data.get('results', None)
assert data['pagination']['total'] == 2
assert results is not None
assert isinstance(results, list)
assert len(results) == n_results
@pytest.mark.parametrize('first, order_by, order', [
('1', 'formula', -1), ('2', 'formula', 1),
('2', 'basis_set', -1), ('1', 'basis_set', 1)])
def test_search_order(self, client, example_elastic_calcs, no_warn, first, order_by, order):
rv = client.get('/repo/?order_by=%s&order=%d' % (order_by, order))
assert rv.status_code == 200
data = json.loads(rv.data)
results = data.get('results', None)
assert data['pagination']['total'] == 2
assert len(results) == 2
assert results[0]['calc_id'] == first
def test_search_user_authrequired(self, client, example_elastic_calcs, no_warn):
rv = client.get('/repo/?owner=user')
assert rv.status_code == 401
......
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