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

Fixed eslinting for ci.

parent 361e2af1
...@@ -55,6 +55,14 @@ linting: ...@@ -55,6 +55,14 @@ linting:
- $CI_COMMIT_REF_NAME =~ /^dev-.*$/ - $CI_COMMIT_REF_NAME =~ /^dev-.*$/
- $CI_COMMIT_MESSAGE =~ /\[skip[ _-]tests?\]/i - $CI_COMMIT_MESSAGE =~ /\[skip[ _-]tests?\]/i
gui_linting:
stage: test
image: node
script:
- cd gui
- yarn
- yarn run eslint 'src/**/*.js'
tests: tests:
stage: test stage: test
image: $TEST_IMAGE image: $TEST_IMAGE
......
...@@ -8,10 +8,16 @@ module.exports = { ...@@ -8,10 +8,16 @@ module.exports = {
} }
}, },
"globals": { "globals": {
"fetch": false "fetch": false,
"browser": true
}, },
"rules": { "rules": {
"space-before-function-paren": ["error", "never"], "space-before-function-paren": ["error", "never"],
"camelcase": [0] "camelcase": [0]
},
"settings": {
"react": {
"version": "detect"
}
} }
} }
\ No newline at end of file
...@@ -91,10 +91,10 @@ class ApiDialogUnstyled extends React.Component { ...@@ -91,10 +91,10 @@ class ApiDialogUnstyled extends React.Component {
<div className={classes.code}> <div className={classes.code}>
<div className={classes.json}> <div className={classes.json}>
<ReactJson <ReactJson
src={data} src={data}
enableClipboard={false} enableClipboard={false}
collapsed={2} collapsed={2}
displayObjectSize={false} displayObjectSize={false}
/> />
</div> </div>
</div> </div>
...@@ -154,10 +154,10 @@ class ApiDialogButtonUnstyled extends React.Component { ...@@ -154,10 +154,10 @@ class ApiDialogButtonUnstyled extends React.Component {
return ( return (
<div className={classes.root}> <div className={classes.root}>
{component ? component({onClick: this.handleShowDialog}) : <Tooltip title="Show API code"> {component ? component({onClick: this.handleShowDialog}) : <Tooltip title="Show API code">
<IconButton onClick={this.handleShowDialog}> <IconButton onClick={this.handleShowDialog}>
<CodeIcon /> <CodeIcon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
} }
<ApiDialog <ApiDialog
{...dialogProps} open={showDialog} {...dialogProps} open={showDialog}
......
...@@ -56,7 +56,7 @@ function ReloadSnack() { ...@@ -56,7 +56,7 @@ function ReloadSnack() {
> >
<SnackbarContent <SnackbarContent
style={{backgroundColor: amber[700]}} style={{backgroundColor: amber[700]}}
message={<span>There is a new NOMAD version. Please press your browser's reload (or even shift+reload) button.</span>} message={<span>There is a new NOMAD version. Please press your browser&apos;s reload (or even shift+reload) button.</span>}
/> />
</Snackbar> </Snackbar>
} }
......
...@@ -39,7 +39,7 @@ class DownloadButton extends React.Component { ...@@ -39,7 +39,7 @@ class DownloadButton extends React.Component {
handleClick(event) { handleClick(event) {
event.stopPropagation() event.stopPropagation()
this.setState({ anchorEl: event.currentTarget }); this.setState({ anchorEl: event.currentTarget })
} }
async handleSelect(choice) { async handleSelect(choice) {
......
...@@ -30,7 +30,7 @@ class FAQ extends React.Component { ...@@ -30,7 +30,7 @@ class FAQ extends React.Component {
### How can I be sure that my data will be cited properly? ### How can I be sure that my data will be cited properly?
Sharing means a change of culture. Making data open access is comparable to a Sharing means a change of culture. Making data open access is comparable to a
publication where references to other work are common practice ever since. publication where references to other work are common practice ever since.
Likewise, using someone's data requires proper citation. We recommend the uploader Likewise, using someone's data requires proper citation. We recommend the uploader
to provide references to their data (publications, websites) and the users to to provide references to their data (publications, websites) and the users to
...@@ -43,7 +43,7 @@ class FAQ extends React.Component { ...@@ -43,7 +43,7 @@ class FAQ extends React.Component {
associated with your data might not change right away, but it will be updated associated with your data might not change right away, but it will be updated
eventually. eventually.
### I'd like to install NOMAD on my local computers to be only used by my group ### I'd like to install NOMAD on my local computers to be only used by my group
Local NOMAD deployments are not actively supported at the moment. However, all Local NOMAD deployments are not actively supported at the moment. However, all
[NOMAD software](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-FAIR) is [NOMAD software](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-FAIR) is
......
export default function ReloadSnack() {
return <Snackbar
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
open
message={<span id="message-id">There is a new version. Please press your browsers Reload (or even Shift+Reload) button.</span>}
/>
}
\ No newline at end of file
...@@ -322,6 +322,8 @@ class Api { ...@@ -322,6 +322,8 @@ class Api {
})) }))
.catch(handleApiError) .catch(handleApiError)
.then(response => { .then(response => {
/* global Blob */
/* eslint no-undef: "error" */
if (response.data instanceof Blob) { if (response.data instanceof Blob) {
if (response.data.type.endsWith('empty')) { if (response.data.type.endsWith('empty')) {
return { return {
...@@ -397,7 +399,9 @@ class Api { ...@@ -397,7 +399,9 @@ class Api {
// this helps to keep consistent values, e.g. in the metadata search view // this helps to keep consistent values, e.g. in the metadata search view
if (response.statistics) { if (response.statistics) {
const empty = {} const empty = {}
Object.keys(response.statistics.total.all).forEach(metric => empty[metric] = 0) Object.keys(response.statistics.total.all).forEach(metric => {
empty[metric] = 0
})
Object.keys(response.statistics) Object.keys(response.statistics)
.filter(key => !['total', 'authors', 'atoms'].includes(key)) .filter(key => !['total', 'authors', 'atoms'].includes(key))
.forEach(key => { .forEach(key => {
......
...@@ -5,7 +5,6 @@ import { Quantity } from '../search/QuantityHistogram' ...@@ -5,7 +5,6 @@ import { Quantity } from '../search/QuantityHistogram'
import SearchContext from '../search/SearchContext' import SearchContext from '../search/SearchContext'
import { withApi } from '../api' import { withApi } from '../api'
class DFTSearchAggregations extends React.Component { class DFTSearchAggregations extends React.Component {
static propTypes = { static propTypes = {
info: PropTypes.object info: PropTypes.object
......
...@@ -7,6 +7,8 @@ import EMSEntryOverview from './ems/EMSEntryOverview' ...@@ -7,6 +7,8 @@ import EMSEntryOverview from './ems/EMSEntryOverview'
import EMSEntryCards from './ems/EMSEntryCards' import EMSEntryCards from './ems/EMSEntryCards'
import DFTSearchByPropertyAggregations from './dft/DFTSearchByPropertyAggregations' import DFTSearchByPropertyAggregations from './dft/DFTSearchByPropertyAggregations'
/* eslint-disable react/display-name */
export const domains = ({ export const domains = ({
dft: { dft: {
name: 'DFT', name: 'DFT',
...@@ -24,7 +26,7 @@ export const domains = ({ ...@@ -24,7 +26,7 @@ export const domains = ({
* onChange (callback to propagate searchValue changes). * onChange (callback to propagate searchValue changes).
*/ */
SearchAggregations: DFTSearchAggregations, SearchAggregations: DFTSearchAggregations,
/** /**
* A component that is used to render the search aggregations by property. * A component that is used to render the search aggregations by property.
*/ */
SearchByPropertyAggregations: DFTSearchByPropertyAggregations, SearchByPropertyAggregations: DFTSearchByPropertyAggregations,
......
...@@ -22,7 +22,6 @@ learn more about NOMAD's archive format [here](/metainfo). ...@@ -22,7 +22,6 @@ learn more about NOMAD's archive format [here](/metainfo).
` `
class MetainfoDialogUnstyled extends React.PureComponent { class MetainfoDialogUnstyled extends React.PureComponent {
static propTypes = { static propTypes = {
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired,
history: PropTypes.object.isRequired, history: PropTypes.object.isRequired,
...@@ -45,7 +44,7 @@ class MetainfoDialogUnstyled extends React.PureComponent { ...@@ -45,7 +44,7 @@ class MetainfoDialogUnstyled extends React.PureComponent {
render() { render() {
const {classes, metaInfoData, onClose} = this.props const {classes, metaInfoData, onClose} = this.props
return <Dialog open className={classes.root}> return <Dialog open className={classes.root}>
<DialogTitle> <DialogTitle>
{metaInfoData.name} {metaInfoData.name}
</DialogTitle> </DialogTitle>
...@@ -142,7 +141,7 @@ class ArchiveEntryView extends React.Component { ...@@ -142,7 +141,7 @@ class ArchiveEntryView extends React.Component {
updateMetaInfo() { updateMetaInfo() {
if (this.props.api && this.props.info && !this.state.metaInfo) { if (this.props.api && this.props.info && !this.state.metaInfo) {
this.props.api.getMetaInfo(this.props.info.domains.find(domain => domain.name === 'dft').metainfo.all_package).then(metaInfo => { // TODO handle the domain specificity this.props.api.getMetaInfo(this.props.info.domains.find(domain => domain.name === 'dft').metainfo.all_package).then(metaInfo => { // TODO handle the domain specificity
if (!this.unmounted) { if (!this.unmounted) {
this.setState({metaInfo: metaInfo}) this.setState({metaInfo: metaInfo})
} }
......
...@@ -209,8 +209,8 @@ class RawFiles extends React.Component { ...@@ -209,8 +209,8 @@ class RawFiles extends React.Component {
downloadUrl = `raw/calc/${uploadId}/${calcId}/*?strip=true` downloadUrl = `raw/calc/${uploadId}/${calcId}/*?strip=true`
} else if (selectedFiles.length > 0) { } else if (selectedFiles.length > 0) {
// use a prefix to shorten the url // use a prefix to shorten the url
const prefix = selectedFiles[0].substring(0, selectedFiles[0].lastIndexOf("/")) const prefix = selectedFiles[0].substring(0, selectedFiles[0].lastIndexOf('/'))
const files = selectedFiles.map(path => path.substring(path.lastIndexOf("/") + 1)).join(',') const files = selectedFiles.map(path => path.substring(path.lastIndexOf('/') + 1)).join(',')
downloadUrl = `raw/${uploadId}?files=${encodeURIComponent(files)}&prefix=${prefix}&strip=true` downloadUrl = `raw/${uploadId}?files=${encodeURIComponent(files)}&prefix=${prefix}&strip=true`
} }
......
...@@ -51,7 +51,7 @@ function getSuggestionValue(suggestion) { ...@@ -51,7 +51,7 @@ function getSuggestionValue(suggestion) {
const styles = theme => ({ const styles = theme => ({
container: { container: {
position: 'relative', position: 'relative'
}, },
suggestionsContainerOpen: { suggestionsContainerOpen: {
position: 'absolute', position: 'absolute',
......
...@@ -161,7 +161,8 @@ export class EntryListUnstyled extends React.Component { ...@@ -161,7 +161,8 @@ export class EntryListUnstyled extends React.Component {
} }
} }
componentWillUpdate(prevProps) { // TODO was this really intentional
UNSAFE_componentWillUpdate(prevProps) {
if (prevProps.data !== this.props.data) { if (prevProps.data !== this.props.data) {
this.setState({selected: []}) this.setState({selected: []})
} }
......
...@@ -35,7 +35,7 @@ const _mapping = { ...@@ -35,7 +35,7 @@ const _mapping = {
'oscillator_strengths': 'Oscillator strengths', 'oscillator_strengths': 'Oscillator strengths',
'transition_dipole_moments': 'Transition dipole moments'} 'transition_dipole_moments': 'Transition dipole moments'}
function map_key (name) { function mapKey(name) {
if (name in _mapping) { if (name in _mapping) {
return _mapping[name] return _mapping[name]
} }
...@@ -102,7 +102,7 @@ class QuantityHistogramUnstyled extends React.Component { ...@@ -102,7 +102,7 @@ class QuantityHistogramUnstyled extends React.Component {
const data = Object.keys(this.props.data) const data = Object.keys(this.props.data)
.map(key => ({ .map(key => ({
name: map_key(key), name: mapKey(key),
value: this.props.data[key][this.props.metric] value: this.props.data[key][this.props.metric]
})) }))
...@@ -247,7 +247,6 @@ class QuantityHistogramUnstyled extends React.Component { ...@@ -247,7 +247,6 @@ class QuantityHistogramUnstyled extends React.Component {
export const QuantityHistogram = withStyles(QuantityHistogramUnstyled.styles)(QuantityHistogramUnstyled) export const QuantityHistogram = withStyles(QuantityHistogramUnstyled.styles)(QuantityHistogramUnstyled)
class QuantityUnstyled extends React.Component { class QuantityUnstyled extends React.Component {
static propTypes = { static propTypes = {
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired,
......
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { withStyles } from '@material-ui/core/styles' import { withStyles } from '@material-ui/core/styles'
/* eslint-disable-next-line */
import { domains } from '../domains' // TODO this causes a weird import bug import { domains } from '../domains' // TODO this causes a weird import bug
import ChipInput from 'material-ui-chip-input' import ChipInput from 'material-ui-chip-input'
import Autosuggest from 'react-autosuggest' import Autosuggest from 'react-autosuggest'
......
...@@ -98,7 +98,7 @@ class UploadsHistogramUnstyled extends React.Component { ...@@ -98,7 +98,7 @@ class UploadsHistogramUnstyled extends React.Component {
} }
] ]
timeInterval = Object.assign({}, ...this.intervals.map(e => ( {[e.value]: e.number}))) timeInterval = Object.assign({}, ...this.intervals.map(e => ({[e.value]: e.number})))
componentDidMount() { componentDidMount() {
const from_time = new Date(this.startDate).getTime() const from_time = new Date(this.startDate).getTime()
...@@ -120,9 +120,7 @@ class UploadsHistogramUnstyled extends React.Component { ...@@ -120,9 +120,7 @@ class UploadsHistogramUnstyled extends React.Component {
handleIntervalChange(newInterval) { handleIntervalChange(newInterval) {
// TODO: add a refresh button so directly updating interval is not necessary // TODO: add a refresh button so directly updating interval is not necessary
this.state.interval = newInterval this.setState({interval: newInterval}, () => this.handleQueryChange())
//this.setState({interval: newInterval})
this.handleQueryChange()
} }
handleTimeChange(newTime, key, target) { handleTimeChange(newTime, key, target) {
...@@ -136,7 +134,7 @@ class UploadsHistogramUnstyled extends React.Component { ...@@ -136,7 +134,7 @@ class UploadsHistogramUnstyled extends React.Component {
key === 'from_time' ? this.setState({from_time: date.getTime()}) : this.setState({until_time: date.getTime()}) key === 'from_time' ? this.setState({from_time: date.getTime()}) : this.setState({until_time: date.getTime()})
} }
if (target === 'picker' || target === 'all') { if (target === 'picker' || target === 'all') {
document.getElementById(key).value = date.toISOString().substring(0,10) document.getElementById(key).value = date.toISOString().substring(0, 10)
} }
} }
...@@ -145,21 +143,21 @@ class UploadsHistogramUnstyled extends React.Component { ...@@ -145,21 +143,21 @@ class UploadsHistogramUnstyled extends React.Component {
if (selected === this.state.time) { if (selected === this.state.time) {
this.props.onChanged(null, null, null) this.props.onChanged(null, null, null)
} else { } else {
const deltaT = this.timeInterval[this.state.interval] const deltaT = this.timeInterval[this.state.interval]
this.handleTimeChange(selected, 'from_time', 'all') this.handleTimeChange(selected, 'from_time', 'all')
this.handleTimeChange(selected + deltaT, 'until_time', 'all') this.handleTimeChange(selected + deltaT, 'until_time', 'all')
this.handleQueryChange() this.handleQueryChange()
} }
} }
resolveDate (name) { resolveDate(name) {
const date = new Date(parseInt(name, 10)) const date = new Date(parseInt(name, 10))
const year = date.toLocaleDateString(undefined, {year: 'numeric'}) const year = date.toLocaleDateString(undefined, {year: 'numeric'})
const month = date.toLocaleDateString(undefined, {month: 'short'}) const month = date.toLocaleDateString(undefined, {month: 'short'})
const day = date.toLocaleDateString(undefined, {day: 'numeric'}) const day = date.toLocaleDateString(undefined, {day: 'numeric'})
const hour = date.toLocaleTimeString(undefined, {hour: 'numeric'}) const hour = date.toLocaleTimeString(undefined, {hour: 'numeric'})
const min = date.toLocaleTimeString(undefined, {minute: 'numeric'}) const min = date.toLocaleTimeString(undefined, {minute: 'numeric'})
const sec= date.toLocaleTimeString(undefined, {second: 'numeric'}) const sec = date.toLocaleTimeString(undefined, {second: 'numeric'})
const intervals = { const intervals = {
'1y': year, '1y': year,
...@@ -173,54 +171,54 @@ class UploadsHistogramUnstyled extends React.Component { ...@@ -173,54 +171,54 @@ class UploadsHistogramUnstyled extends React.Component {
return intervals[this.state.interval] return intervals[this.state.interval]
} }
hover (svg, bar) { hover(svg, bar) {
const textOffset = 25 const textOffset = 25
const tooltip = svg.append('g') const tooltip = svg.append('g')
.attr('class', 'tooltip') .attr('class', 'tooltip')
.style('display', 'none') .style('display', 'none')
const hoverBox = tooltip.append('rect') const hoverBox = tooltip.append('rect')
.attr('width', 10) .attr('width', 10)
.attr('height', 20) .attr('height', 20)
.attr('fill', 'white') .attr('fill', 'white')
.style('opacity', 0.0) .style('opacity', 0.0)
const text = tooltip.append('text') const text = tooltip.append('text')
.attr('x', textOffset) .attr('x', textOffset)
.attr('dy', '1.2em') .attr('dy', '1.2em')
.style('text-anchor', 'start') .style('text-anchor', 'start')
.attr('font-size', '12px') .attr('font-size', '12px')
//.attr('font-weight', 'bold') // .attr('font-weight', 'bold')
bar bar
.on('mouseover', () => { .on('mouseover', () => {
tooltip.style('display', null) tooltip.style('display', null)
let { width } = text.node().getBBox() let { width } = text.node().getBBox()
hoverBox.attr('width', `${ width + textOffset }px`) hoverBox.attr('width', `${width + textOffset}px`)
}) })
.on('mouseout', () => tooltip.style('display', 'none')) .on('mouseout', () => tooltip.style('display', 'none'))
.on('mousemove', function(d) { .on('mousemove', function(d) {
let xPosition = d3.mouse(this)[0] - 15 let xPosition = d3.mouse(this)[0] - 15
let yPosition = d3.mouse(this)[1] - 25 let yPosition = d3.mouse(this)[1] - 25
tooltip.attr('transform', `translate( ${ xPosition }, ${ yPosition })`) tooltip.attr('transform', `translate( ${xPosition}, ${yPosition})`)
tooltip.attr('data-html', 'true') tooltip.attr('data-html', 'true')
tooltip.select('text').text( new Date(d.time).toISOString() + ': ' + d.value ) tooltip.select('text').text(new Date(d.time).toISOString() + ': ' + d.value)
}) })
} }
updateChart () { updateChart() {
let data = [] let data = []
if (! this.props.data) { if (!this.props.data) {
return return
} else { } else {
data = Object.keys(this.props.data).map(key => ({ data = Object.keys(this.props.data).map(key => ({
time: parseInt(key, 10), time: parseInt(key, 10),
name: this.resolveDate(key), name: this.resolveDate(key),
value: this.props.data[key][this.props.metric] value: this.props.data[key][this.props.metric]
}))} }))
}
data.sort((a, b) => d3.ascending(a.time, b.time)) data.sort((a, b) => d3.ascending(a.time, b.time))
if (data.length > 0) { if (data.length > 0) {
...@@ -228,13 +226,13 @@ class UploadsHistogramUnstyled extends React.Component { ...@@ -228,13 +226,13 @@ class UploadsHistogramUnstyled extends React.Component {
this.handleTimeChange(this.state.until_time, 'until_time', 'picker') this.handleTimeChange(this.state.until_time, 'until_time', 'picker')
} }
const scalePower = this.state.scalePower const scalePower = this.state.scalePower
const width = this.container.current.offsetWidth const width = this.container.current.offsetWidth
const height = this.props.height const height = this.props.height
const margin = Math.round(0.1*height) const margin = Math.round(0.1 * height)
const x = scaleBand().rangeRound([margin, width]).padding(0.1) const x = scaleBand().rangeRound([margin, width]).padding(0.1)
const y = scalePow().range([height-margin, margin]).exponent(scalePower) const y = scalePow().range([height - margin, margin]).exponent(scalePower)
const max = d3.max(data, d => d.value) || 0 const max = d3.max(data, d => d.value) || 0
x.domain(data.map(d => d.name)) x.domain(data.map(d => d.name))
...@@ -247,36 +245,36 @@ class UploadsHistogramUnstyled extends React.Component { ...@@ -247,36 +245,36 @@ class UploadsHistogramUnstyled extends React.Component {
const xAxis = d3.axisBottom(x) const xAxis = d3.axisBottom(x)
svg.select('.xaxis').remove() svg.select('.xaxis').remove()
svg.append('g') svg.append('g')
.attr('transform', `translate(0,${height-margin})`) .attr('transform', `translate(0,${height - margin})`)