Commit 0600823c authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Various refactorings and fixes in GUI due to latest API changes.

parent 278fb1f7
Pipeline #41239 failed with stages
in 17 minutes and 32 seconds
...@@ -24,10 +24,9 @@ ...@@ -24,10 +24,9 @@
"url-parse": "^1.4.3" "url-parse": "^1.4.3"
}, },
"scripts": { "scripts": {
"metainfo": "git clone --single-branch -b nomad-fair http://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-info.git --depth=1 public/metainfo",
"gitinfo": "echo \"{ \\\"log\\\": \\\"$(git log -1 --oneline)\\\", \\\"ref\\\": \\\"$(git describe --all)\\\", \\\"version\\\": \\\"$(git describe)\\\" }\" > src/gitinfo.json", "gitinfo": "echo \"{ \\\"log\\\": \\\"$(git log -1 --oneline)\\\", \\\"ref\\\": \\\"$(git describe --all)\\\", \\\"version\\\": \\\"$(git describe)\\\" }\" > src/gitinfo.json",
"start": "yarn metainfo; react-scripts start", "start": "react-scripts start",
"build": "yarn metainfo; react-scripts build", "build": "react-scripts build",
"test": "react-scripts test --env=jsdom", "test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject" "eject": "react-scripts eject"
}, },
......
import { UploadRequest } from '@navjobs/upload' import { UploadRequest } from '@navjobs/upload'
import Swagger from 'swagger-client' import Swagger from 'swagger-client'
import { apiBase, appStaticBase } from './config' import { apiBase } from './config'
const auth_headers = { const auth_headers = {
Authorization: 'Basic ' + btoa('sheldon.cooper@nomad-fairdi.tests.de:password') Authorization: 'Basic ' + btoa('sheldon.cooper@nomad-fairdi.tests.de:password')
...@@ -19,29 +19,31 @@ const swaggerPromise = Swagger(`${apiBase}/swagger.json`, { ...@@ -19,29 +19,31 @@ const swaggerPromise = Swagger(`${apiBase}/swagger.json`, {
}) })
const networkError = (e) => { const networkError = (e) => {
console.log(e)
throw Error('Network related error, cannot reach API: ' + e) throw Error('Network related error, cannot reach API: ' + e)
} }
const handleJsonErrors = () => { const handleJsonErrors = (e) => {
throw Error('Server return unexpected data format.') console.log(e)
throw Error('API return unexpected data format.')
} }
const handleResponseErrors = (response) => { const handleResponseErrors = (response) => {
if (!response.ok) { if (!response.ok) {
return response.json() return response.json()
.catch(() => { .catch(() => {
throw Error(`API/object storage error (${response.status}): ${response.statusText}`) throw Error(`API error (${response.status}): ${response.statusText}`)
}).then(data => { }).then(data => {
throw Error(`API/object storage error (${response.status}): ${data.message}`) throw Error(`API error (${response.status}): ${data.message}`)
}) })
} }
return response return response
} }
class Upload { class Upload {
constructor(json, created) { constructor(json) {
this.uploading = 0 this.uploading = 0
this._assignFromJson(json, created) this._assignFromJson(json)
} }
uploadFile(file) { uploadFile(file) {
...@@ -58,7 +60,6 @@ class Upload { ...@@ -58,7 +60,6 @@ class Upload {
}, },
files: [file], files: [file],
progress: value => { progress: value => {
console.log(value)
this.uploading = value this.uploading = value
} }
} }
...@@ -77,41 +78,39 @@ class Upload { ...@@ -77,41 +78,39 @@ class Upload {
.then(() => this) .then(() => this)
} }
_assignFromJson(uploadJson, created) { _assignFromJson(uploadJson) {
Object.assign(this, uploadJson) Object.assign(this, uploadJson)
if (this.current_task !== this.tasks[0]) { if (this.calcs) {
this.uploading = 100 this.calcs.results.forEach(calc => {
this.waiting = false const archiveId = calc.archive_id.split('/')
} else { calc.upload_hash = archiveId[0]
this.waiting = true calc.calc_hash = archiveId[1]
})
} }
} }
get(page, perPage, orderBy, order) { get(page, perPage, orderBy, order) {
if (!page) page = 1
if (!perPage) perPage = 5
if (!orderBy) orderBy = 'mainfile'
if (!order) order = 'desc'
order = order === 'desc' ? -1 : 1
if (this.uploading !== null && this.uploading !== 100) { if (this.uploading !== null && this.uploading !== 100) {
return new Promise(resolve => resolve(this)) return new Promise(resolve => resolve(this))
} else { } else {
const qparams = `page=${page}&per_page=${perPage}&order_by=${orderBy}&order=${order}` if (this.upload_id) {
return fetch( return swaggerPromise.then(client => client.apis.uploads.get_upload({
`${apiBase}/uploads/${this.upload_id}?${qparams}`, upload_id: this.upload_id,
{ page: page || 1,
method: 'GET', per_page: perPage || 5,
headers: auth_headers order_by: orderBy || 'mainfile',
}) order: order || -1
.catch(networkError) }))
.then(handleResponseErrors) .catch(networkError)
.then(response => response.json()) .then(handleResponseErrors)
.then(uploadJson => { .then(response => response.body)
this._assignFromJson(uploadJson) .then(uploadJson => {
return this this._assignFromJson(uploadJson)
}) return this
})
} else {
return new Promise(resolve => resolve(this))
}
} }
} }
} }
...@@ -119,33 +118,43 @@ class Upload { ...@@ -119,33 +118,43 @@ class Upload {
function createUpload(name) { function createUpload(name) {
return new Upload({ return new Upload({
name: name, name: name,
tasks: ['UPLOADING'], tasks: ['uploading'],
current_task: 'UPLOADING' current_task: 'uploading',
uploading: 0,
create_time: new Date()
}, true) }, true)
} }
function getUploads() { async function getUploads() {
return fetch( const client = await swaggerPromise
`${apiBase}/uploads/`, return client.apis.uploads.get_uploads()
{
method: 'GET',
headers: auth_headers
})
.catch(networkError) .catch(networkError)
.then(handleResponseErrors) .then(handleResponseErrors)
.then(response => response.json()) .then(response => response.body.map(uploadJson => {
.then(uploadsJson => uploadsJson.map(uploadJson => new Upload(uploadJson))) const upload = new Upload(uploadJson)
upload.uploading = 100
return upload
}))
} }
function archive(uploadHash, calcHash) { async function archive(uploadHash, calcHash) {
return fetch(archiveUrl(uploadHash, calcHash)) const client = await swaggerPromise
return client.apis.archive.get_archive_calc({
upload_hash: uploadHash,
calc_hash: calcHash
})
.catch(networkError) .catch(networkError)
.then(handleResponseErrors) .then(handleResponseErrors)
.then(response => response.json()) .then(response => response.body)
} }
function calcProcLog(archiveId) { async function calcProcLog(uploadHash, calcHash) {
return fetch(`${apiBase}/archive/logs/${archiveId}`) const client = await swaggerPromise
console.log(uploadHash + calcHash)
return client.apis.archive.get_archive_logs({
upload_hash: uploadHash,
calc_hash: calcHash
})
.catch(networkError) .catch(networkError)
.then(response => { .then(response => {
if (!response.ok) { if (!response.ok) {
...@@ -155,62 +164,53 @@ function calcProcLog(archiveId) { ...@@ -155,62 +164,53 @@ function calcProcLog(archiveId) {
return handleResponseErrors(response) return handleResponseErrors(response)
} }
} else { } else {
return response.text() return response.text
} }
}) })
} }
function archiveUrl(uploadHash, calcHash) { async function repo(uploadHash, calcHash) {
return `${apiBase}/archive/${uploadHash}/${calcHash}` const client = await swaggerPromise
} return client.apis.repo.get_repo_calc({
upload_hash: uploadHash,
function repo(uploadHash, calcHash) { calc_hash: calcHash
return fetch(`${apiBase}/repo/${uploadHash}/${calcHash}`) })
.catch(networkError) .catch(networkError)
.then(handleResponseErrors) .then(handleResponseErrors)
.then(response => response.json()) .then(response => response.body)
} }
function repoAll(page, perPage, owner) { async function repoAll(page, perPage, owner) {
return fetch( const client = await swaggerPromise
`${apiBase}/repo/?page=${page}&per_page=${perPage}&owner=${owner || 'all'}`, return client.apis.repo.get_calcs({
{ page: page,
method: 'GET', per_page: perPage,
headers: auth_headers ower: owner || 'all'
}) })
.catch(networkError) .catch(networkError)
.then(handleResponseErrors) .then(handleResponseErrors)
.then(response => response.json()) .then(response => response.body)
} }
function deleteUpload(uploadId) { async function deleteUpload(uploadId) {
return fetch( const client = await swaggerPromise
`${apiBase}/uploads/${uploadId}`, return client.apis.uploads.delete_upload({upload_id: uploadId})
{
method: 'DELETE',
headers: auth_headers
})
.catch(networkError) .catch(networkError)
.then(handleResponseErrors) .then(handleResponseErrors)
.then(response => response.json()) .then(response => response.body)
} }
function unstageUpload(uploadId) { async function unstageUpload(uploadId) {
return fetch( const client = await swaggerPromise
`${apiBase}/uploads/${uploadId}`, return client.apis.uploads.exec_upload_command({
{ upload_id: uploadId,
method: 'POST', payload: {
body: JSON.stringify({
operation: 'unstage' operation: 'unstage'
}),
headers: {
'Content-Type': 'application/json',
...auth_headers
} }
}) })
.catch(networkError) .catch(networkError)
.then(handleResponseErrors) .then(handleResponseErrors)
.then(response => response.json()) .then(response => response.body)
} }
let cachedMetaInfo = null let cachedMetaInfo = null
...@@ -220,7 +220,7 @@ async function getMetaInfo() { ...@@ -220,7 +220,7 @@ async function getMetaInfo() {
return cachedMetaInfo return cachedMetaInfo
} else { } else {
const loadMetaInfo = async(path) => { const loadMetaInfo = async(path) => {
return fetch(`${appStaticBase}/metainfo/meta_info/nomad_meta_info/${path}`) return fetch(`${apiBase}/archive/metainfo/${path}`)
.catch(networkError) .catch(networkError)
.then(handleResponseErrors) .then(handleResponseErrors)
.then(response => response.json()) .then(response => response.json())
...@@ -262,7 +262,6 @@ const api = { ...@@ -262,7 +262,6 @@ const api = {
getUploads: getUploads, getUploads: getUploads,
archive: archive, archive: archive,
calcProcLog: calcProcLog, calcProcLog: calcProcLog,
archiveUrl: archiveUrl,
repo: repo, repo: repo,
repoAll: repoAll, repoAll: repoAll,
getMetaInfo: getMetaInfo getMetaInfo: getMetaInfo
......
...@@ -103,8 +103,7 @@ class ArchiveCalc extends React.Component { ...@@ -103,8 +103,7 @@ class ArchiveCalc extends React.Component {
*quantities* by visiting the [meta-info](/metainfo) browser. *quantities* by visiting the [meta-info](/metainfo) browser.
The tree below shows all calculation data in nomad's *hierachical* and The tree below shows all calculation data in nomad's *hierachical* and
*code independent* archive format. You can download it *code independent* archive format. Click on values to
[here](${api.archiveUrl(uploadHash, calcHash)}). Click on values to
see a *meta-info* description. see a *meta-info* description.
`}</Markdown> `}</Markdown>
<Typography className={classes.logLink}> <Typography className={classes.logLink}>
...@@ -124,7 +123,8 @@ class ArchiveCalc extends React.Component { ...@@ -124,7 +123,8 @@ class ArchiveCalc extends React.Component {
</Paper> </Paper>
<CalcProcLogPopper <CalcProcLogPopper
open={this.state.showLogs} open={this.state.showLogs}
archiveId={`${uploadHash}/${calcHash}`} uploadHash={uploadHash}
calcHash={calcHash}
onClose={() => this.setState({showLogs: false})} onClose={() => this.setState({showLogs: false})}
anchorEl={this.logPopperAnchor.current} anchorEl={this.logPopperAnchor.current}
raiseError={this.props.raiseError} raiseError={this.props.raiseError}
......
...@@ -10,7 +10,6 @@ import Link from 'react-router-dom/Link' ...@@ -10,7 +10,6 @@ import Link from 'react-router-dom/Link'
class CalcLink extends React.Component { class CalcLink extends React.Component {
static propTypes = { static propTypes = {
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired,
calcId: PropTypes.string,
uploadHash: PropTypes.string, uploadHash: PropTypes.string,
calcHash: PropTypes.string, calcHash: PropTypes.string,
disabled: PropTypes.bool disabled: PropTypes.bool
...@@ -24,19 +23,18 @@ class CalcLink extends React.Component { ...@@ -24,19 +23,18 @@ class CalcLink extends React.Component {
}); });
render() { render() {
const { uploadHash, calcHash, classes, calcId, disabled } = this.props const { uploadHash, calcHash, classes, disabled } = this.props
const id = calcId || `${uploadHash}/${calcHash}`
return ( return (
<div className={classes.root}> <div className={classes.root}>
<MuiThemeProvider theme={repoTheme}> <MuiThemeProvider theme={repoTheme}>
<IconButton color="primary" component={Link} to={`/repo/${id}`} disabled={disabled}><RepoIcon /></IconButton> <IconButton color="primary" component={Link} to={`/repo/${uploadHash}/${calcHash}`} disabled={disabled}><RepoIcon /></IconButton>
</MuiThemeProvider> </MuiThemeProvider>
<MuiThemeProvider theme={archiveTheme}> <MuiThemeProvider theme={archiveTheme}>
<IconButton color="primary" component={Link} to={`/archive/${id}`} disabled={disabled}><ArchiveIcon /></IconButton> <IconButton color="primary" component={Link} to={`/archive/${uploadHash}/${calcHash}`} disabled={disabled}><ArchiveIcon /></IconButton>
</MuiThemeProvider> </MuiThemeProvider>
<MuiThemeProvider theme={encTheme}> <MuiThemeProvider theme={encTheme}>
<IconButton color="primary" component={Link} to={`/enc/${id}`} disabled={disabled}><EncIcon /></IconButton> <IconButton color="primary" component={Link} to={`/enc/${uploadHash}/${calcHash}`} disabled={disabled}><EncIcon /></IconButton>
</MuiThemeProvider> </MuiThemeProvider>
</div> </div>
) )
......
...@@ -11,7 +11,8 @@ class CalcProcLogPopper extends React.Component { ...@@ -11,7 +11,8 @@ class CalcProcLogPopper extends React.Component {
static propTypes = { static propTypes = {
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired,
raiseError: PropTypes.func.isRequired, raiseError: PropTypes.func.isRequired,
archiveId: PropTypes.string.isRequired, uploadHash: PropTypes.string.isRequired,
calcHash: PropTypes.string.isRequired,
open: PropTypes.bool, open: PropTypes.bool,
onClose: PropTypes.func, onClose: PropTypes.func,
anchorEl: PropTypes.any anchorEl: PropTypes.any
...@@ -28,8 +29,8 @@ class CalcProcLogPopper extends React.Component { ...@@ -28,8 +29,8 @@ class CalcProcLogPopper extends React.Component {
} }
componentDidMount() { componentDidMount() {
const {archiveId} = this.props const {uploadHash, calcHash} = this.props
api.calcProcLog(archiveId).then(logs => { api.calcProcLog(uploadHash, calcHash).then(logs => {
if (logs && logs !== '') { if (logs && logs !== '') {
this.setState({logs: logs}) this.setState({logs: logs})
} }
......
...@@ -80,7 +80,7 @@ class Upload extends React.Component { ...@@ -80,7 +80,7 @@ class Upload extends React.Component {
orderBy: 'status', orderBy: 'status',
order: 'asc' order: 'asc'
}, },
archiveLogs: null, // archive id of archive to show logs for archiveLogs: null, // { uploadHash, calcHash } ids of archive to show logs for
loading: true, // its loading data from the server and the user should know about it loading: true, // its loading data from the server and the user should know about it
updating: true // it is still not complete and continieusly looking for updates updating: true // it is still not complete and continieusly looking for updates
} }
...@@ -94,7 +94,7 @@ class Upload extends React.Component { ...@@ -94,7 +94,7 @@ class Upload extends React.Component {
const {page, perPage, orderBy, order} = params const {page, perPage, orderBy, order} = params
this.setState({loading: true}) this.setState({loading: true})
this.state.upload.get(page, perPage, orderBy, order) this.state.upload.get(page, perPage, orderBy, order === 'asc' ? 1 : -1)
.then(upload => { .then(upload => {
if (!this._unmounted) { if (!this._unmounted) {
const continueUpdating = upload.status !== 'SUCCESS' && upload.status !== 'FAILURE' && !upload.is_stale const continueUpdating = upload.status !== 'SUCCESS' && upload.status !== 'FAILURE' && !upload.is_stale
...@@ -169,7 +169,7 @@ class Upload extends React.Component { ...@@ -169,7 +169,7 @@ class Upload extends React.Component {
renderStepper() { renderStepper() {
const { classes } = this.props const { classes } = this.props
const { upload } = this.state const { upload } = this.state
const { calcs, tasks, current_task, status, errors, waiting } = upload const { calcs, tasks, current_task, status, errors } = upload
let activeStep = tasks.indexOf(current_task) let activeStep = tasks.indexOf(current_task)
activeStep += (status === 'SUCCESS') ? 1 : 0 activeStep += (status === 'SUCCESS') ? 1 : 0
...@@ -181,7 +181,7 @@ class Upload extends React.Component { ...@@ -181,7 +181,7 @@ class Upload extends React.Component {
if (upload.status !== 'FAILURE') { if (upload.status !== 'FAILURE') {
props.optional = ( props.optional = (
<Typography variant="caption"> <Typography variant="caption">
{waiting ? 'waiting for upload' : `${uploading || 0}%`} {uploading === 100 && current_task === tasks[0] ? 'waiting for processing ...' : `${uploading || 0}%`}
</Typography> </Typography>
) )
} }
...@@ -292,7 +292,7 @@ class Upload extends React.Component { ...@@ -292,7 +292,7 @@ class Upload extends React.Component {
} }
const renderRow = (calc, index) => { const renderRow = (calc, index) => {
const { mainfile, archive_id, parser, tasks, current_task, status, errors } = calc const { mainfile, calc_hash, upload_hash, parser, tasks, current_task, status, errors } = calc
const color = status === 'FAILURE' ? 'error' : 'default' const color = status === 'FAILURE' ? 'error' : 'default'
const row = ( const row = (
<TableRow key={index}> <TableRow key={index}>
...@@ -301,7 +301,7 @@ class Upload extends React.Component { ...@@ -301,7 +301,7 @@ class Upload extends React.Component {
{mainfile} {mainfile}
</Typography> </Typography>
<Typography variant="caption" color={color}> <Typography variant="caption" color={color}>
{archive_id} {upload_hash}/{calc_hash}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell> <TableCell>
...@@ -324,7 +324,7 @@ class Upload extends React.Component { ...@@ -324,7 +324,7 @@ class Upload extends React.Component {
<Typography color={color}> <Typography color={color}>
{(status === 'SUCCESS' || status === 'FAILURE') {(status === 'SUCCESS' || status === 'FAILURE')
? ?
<a className={classes.logLink} href="#logs" onClick={() => this.setState({archiveLogs: archive_id})}> <a className={classes.logLink} href="#logs" onClick={() => this.setState({archiveLogs: { uploadHash: upload_hash, calcHash: calc_hash }})}>
{status.toLowerCase()} {status.toLowerCase()}
</a> </a>
: status.toLowerCase() : status.toLowerCase()
...@@ -332,14 +332,14 @@ class Upload extends React.Component { ...@@ -332,14 +332,14 @@ class Upload extends React.Component {
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell> <TableCell>
<CalcLinks calcId={archive_id} disabled={status !== 'SUCCESS'} /> <CalcLinks uploadHash={upload_hash} calcHash={calc_hash} disabled={status !== 'SUCCESS'} />
</TableCell> </TableCell>
</TableRow> </TableRow>
) )
if (status === 'FAILURE') { if (status === 'FAILURE') {
return (