Skip to content
Snippets Groups Projects
Unverified Commit a8cd5eb1 authored by Martin Weise's avatar Martin Weise
Browse files

Fixed the frontend for docker container unavailability

parent 7d084235
Branches
Tags
4 merge requests!129New module for citation as they occur multiple,!121Modified logging, modified logging level, modified flasgger endpoint,!113Resolve "Bugs related with Query Service",!112Resolve "Bugs related with Query Service"
...@@ -158,13 +158,13 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler { ...@@ -158,13 +158,13 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus()); return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
} }
@ResponseStatus(HttpStatus.CONFLICT) @ResponseStatus(HttpStatus.GATEWAY_TIMEOUT)
@ExceptionHandler(QueryStoreException.class) @ExceptionHandler(QueryStoreException.class)
public ResponseEntity<ApiErrorDto> handle(QueryStoreException e, WebRequest request) { public ResponseEntity<ApiErrorDto> handle(QueryStoreException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder() final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.CONFLICT) .status(HttpStatus.GATEWAY_TIMEOUT)
.message(e.getLocalizedMessage()) .message(e.getLocalizedMessage())
.code("error.query.storeexists") .code("error.query.store")
.build(); .build();
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus()); return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
} }
......
...@@ -3,7 +3,7 @@ package at.tuwien.exception; ...@@ -3,7 +3,7 @@ package at.tuwien.exception;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(code = HttpStatus.CONFLICT) @ResponseStatus(code = HttpStatus.GATEWAY_TIMEOUT)
public class QueryStoreException extends Exception { public class QueryStoreException extends Exception {
public QueryStoreException(String msg) { public QueryStoreException(String msg) {
......
...@@ -59,7 +59,7 @@ public class StoreServiceImpl extends HibernateConnector implements StoreService ...@@ -59,7 +59,7 @@ public class StoreServiceImpl extends HibernateConnector implements StoreService
return storeMapper.resultSetToQueryList(resultSet); return storeMapper.resultSetToQueryList(resultSet);
} catch (SQLException e) { } catch (SQLException e) {
log.error("Failed to find queries: {}", e.getMessage()); log.error("Failed to find queries: {}", e.getMessage());
throw new QueryStoreException("Failed to find queries"); throw new QueryStoreException("Failed to find queries: " + e.getMessage());
} finally { } finally {
dataSource.close(); dataSource.close();
} }
......
<template> <template>
<div> <div>
<v-progress-linear v-if="loading" indeterminate /> <v-progress-linear v-if="loading || error" :color="loadingColor" :value="loadProgress" />
<v-tabs-items> <v-tabs-items>
<v-card v-if="!loading && queries.length === 0" flat> <v-card v-if="!loading && queries.length === 0" flat>
<v-card-text v-text="emptyMessage" /> <v-card-text v-text="emptyMessage" />
</v-card> </v-card>
<v-expansion-panels v-if="!loading && queries.length > 0" accordion> <v-expansion-panels v-if="queries.length > 0" accordion>
<v-expansion-panel v-for="(item, i) in queries" :key="i" @click="details(item)"> <v-expansion-panel v-for="(item, i) in queries" :key="i" @click="details(item)">
<v-expansion-panel-header> <v-expansion-panel-header>
<pre>{{ item.query }}</pre> <pre>{{ item.query }}</pre>
...@@ -91,6 +91,8 @@ export default { ...@@ -91,6 +91,8 @@ export default {
data () { data () {
return { return {
loading: false, loading: false,
loadProgress: 0,
error: false,
queries: [], queries: [],
user: { user: {
username: null username: null
...@@ -127,6 +129,9 @@ export default { ...@@ -127,6 +129,9 @@ export default {
headers: { Authorization: `Bearer ${this.token}` } headers: { Authorization: `Bearer ${this.token}` }
} }
}, },
loadingColor () {
return this.error ? 'error' : 'primary'
},
executionUTC () { executionUTC () {
return formatTimestampUTCLabel(this.queryDetails.execution) return formatTimestampUTCLabel(this.queryDetails.execution)
}, },
...@@ -146,8 +151,11 @@ export default { ...@@ -146,8 +151,11 @@ export default {
mounted () { mounted () {
this.loadUser() this.loadUser()
this.loadDatabase() this.loadDatabase()
.then(() => this.loadQueries())
.then(() => this.loadIdentifiers()) .then(() => this.loadIdentifiers())
.then(() => {
this.simulateProgress()
this.loadQueries()
})
}, },
methods: { methods: {
async loadQueries () { async loadQueries () {
...@@ -157,10 +165,17 @@ export default { ...@@ -157,10 +165,17 @@ export default {
try { try {
this.loading = true this.loading = true
const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/query?persisted=true`, this.config) const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/query?persisted=true`, this.config)
this.queries = res.data res.data.forEach((query) => {
if (this.queries.filter(q => q.id === query.id).length > 0) {
return
}
this.queries.push(query)
})
console.debug('queries', this.queries) console.debug('queries', this.queries)
} catch (err) { } catch (err) {
this.$toast.error('Could not list queries') this.error = true
console.error('Connection to query store failed', err.response.data)
this.$toast.error(err.response.data.message)
} }
this.loading = false this.loading = false
}, },
...@@ -172,15 +187,24 @@ export default { ...@@ -172,15 +187,24 @@ export default {
this.loading = true this.loading = true
const res = await this.$axios.get(`/api/identifier?dbid=${this.$route.params.database_id}`, this.config) const res = await this.$axios.get(`/api/identifier?dbid=${this.$route.params.database_id}`, this.config)
const identifiers = res.data.filter(i => i.type === 'subset') const identifiers = res.data.filter(i => i.type === 'subset')
this.queries.forEach((query) => { const queries = identifiers.map((identifier) => {
const id = identifiers.filter(i => i.container_id === query.cid && i.database_id === query.dbid && i.query_id === query.id) const query = {
if (id.length === 1) { id: identifier.query_id,
query.identifier = id[0] identifier,
type: identifier.type,
query: identifier.query,
query_hash: identifier.query_hash,
result_hash: identifier.result_hash,
created: identifier.created,
execution: identifier.execution
} }
return query
}) })
console.debug('identifiers', identifiers) this.queries = queries
console.debug('identifier queries', queries)
} catch (err) { } catch (err) {
this.$toast.error('Could not list identifiers') console.error('Failed to load identifiers', err.response.data)
this.$toast.error('Failed to load identifiers')
} }
this.loading = false this.loading = false
}, },
...@@ -205,6 +229,20 @@ export default { ...@@ -205,6 +229,20 @@ export default {
} }
this.user.username = decodeJwt(this.token).sub this.user.username = decodeJwt(this.token).sub
}, },
simulateProgress () {
if (this.loadProgress !== 0) {
return
}
const timeout = 30 * 1000 /* ms */
const ticks = 100 /* ms */
let i = 0
setInterval(() => {
if (i++ >= timeout && !this.error) {
return
}
this.loadProgress = ((i * 100) / timeout) * 100
}, ticks)
},
async loadDatabase () { async loadDatabase () {
try { try {
this.loading = true this.loading = true
...@@ -213,7 +251,7 @@ export default { ...@@ -213,7 +251,7 @@ export default {
console.debug('database', this.database) console.debug('database', this.database)
} catch (err) { } catch (err) {
this.error = true this.error = true
this.$toast.error('Could not get database details.') this.$toast.error('Could not get database details')
} }
this.loading = false this.loading = false
} }
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
</v-btn> </v-btn>
</v-toolbar-title> </v-toolbar-title>
</v-toolbar> </v-toolbar>
<v-progress-linear v-if="loadingQuery || loadingIdentifier || loadingDatabase || error" :color="loadingColor" :value="loadProgress" />
<v-card flat tile> <v-card flat tile>
<v-card-title> <v-card-title>
Subset Information Subset Information
...@@ -158,22 +159,22 @@ ...@@ -158,22 +159,22 @@
Query Statement Query Statement
</v-list-item-title> </v-list-item-title>
<v-list-item-content> <v-list-item-content>
<v-skeleton-loader v-if="loadingQuery" type="text" class="skeleton-large" /> <v-skeleton-loader v-if="!query_statement" type="text" class="skeleton-large" />
<pre v-if="!loadingQuery">{{ query_statement }}</pre> <pre v-if="query_statement">{{ query_statement }}</pre>
</v-list-item-content> </v-list-item-content>
<v-list-item-title class="mt-2"> <v-list-item-title class="mt-2">
Subset Hash Subset Hash
</v-list-item-title> </v-list-item-title>
<v-list-item-content> <v-list-item-content>
<v-skeleton-loader v-if="loadingQuery" type="text" class="skeleton-medium" /> <v-skeleton-loader v-if="!query_hash" type="text" class="skeleton-medium" />
<pre v-if="!loadingQuery">{{ query_hash }}</pre> <pre v-if="query_hash">{{ query_hash }}</pre>
</v-list-item-content> </v-list-item-content>
<v-list-item-title class="mt-2"> <v-list-item-title class="mt-2">
Subset Creator Subset Creator
</v-list-item-title> </v-list-item-title>
<v-list-item-content> <v-list-item-content>
<v-skeleton-loader v-if="loadingQuery" type="text" class="skeleton-small" /> <v-skeleton-loader v-if="!creator" type="text" class="skeleton-small" />
<span v-if="!loadingQuery"> <span v-if="creator">
{{ creator }} <sup> {{ creator }} <sup>
<v-icon v-if="database.creator.email_verified" small color="primary">mdi-check-decagram</v-icon> <v-icon v-if="database.creator.email_verified" small color="primary">mdi-check-decagram</v-icon>
</sup> </sup>
...@@ -183,8 +184,8 @@ ...@@ -183,8 +184,8 @@
Subset Creation Subset Creation
</v-list-item-title> </v-list-item-title>
<v-list-item-content> <v-list-item-content>
<v-skeleton-loader v-if="loadingQuery" type="text" class="skeleton-small" /> <v-skeleton-loader v-if="!executionUTC" type="text" class="skeleton-small" />
<span v-if="!loadingQuery">{{ executionUTC }}</span> <span v-if="executionUTC">{{ executionUTC }}</span>
</v-list-item-content> </v-list-item-content>
</v-list-item-content> </v-list-item-content>
</v-list-item> </v-list-item>
...@@ -300,11 +301,16 @@ export default { ...@@ -300,11 +301,16 @@ export default {
query_normalized: null, query_normalized: null,
query_hash: null, query_hash: null,
result_number: null, result_number: null,
result_hash: null,
execution: null, execution: null,
publication_year: null, publication_year: null,
publication_month: null, publication_month: null,
publication_day: null, publication_day: null,
related: [], related: [],
creator: {
username: null,
id: null
},
doi: null, doi: null,
creators: [] creators: []
}, },
...@@ -330,6 +336,7 @@ export default { ...@@ -330,6 +336,7 @@ export default {
metadataLoading: false, metadataLoading: false,
downloadLoading: false, downloadLoading: false,
error: false, error: false,
loadProgress: 0,
promises: [] promises: []
} }
}, },
...@@ -341,7 +348,7 @@ export default { ...@@ -341,7 +348,7 @@ export default {
return location.protocol + '//' + location.host return location.protocol + '//' + location.host
}, },
loadingColor () { loadingColor () {
return this.error ? 'red' : 'primary' return this.error ? 'error' : 'primary'
}, },
token () { token () {
return this.$store.state.token return this.$store.state.token
...@@ -428,6 +435,13 @@ export default { ...@@ -428,6 +435,13 @@ export default {
return this.identifier.id ? formatTimestampUTCLabel(this.identifier.execution) : formatTimestampUTCLabel(this.query.execution) return this.identifier.id ? formatTimestampUTCLabel(this.identifier.execution) : formatTimestampUTCLabel(this.query.execution)
}, },
creator () { creator () {
if (this.identifier.creator.username !== null) {
if (this.identifier.creator.firstname === null || this.identifier.creator.lastname === null) {
return this.identifier.creator.username
} else {
return this.identifier.creator.firstname + ' ' + this.identifier.creator.lastname
}
}
if (this.query.creator.username === null) { if (this.query.creator.username === null) {
return null return null
} }
...@@ -440,15 +454,21 @@ export default { ...@@ -440,15 +454,21 @@ export default {
return this.identifier.id ? this.identifier.creators : null return this.identifier.id ? this.identifier.creators : null
}, },
erroneous () { erroneous () {
if (this.identifier.result_number) {
return false
}
return !this.query.result_hash return !this.query.result_hash
} }
}, },
mounted () { mounted () {
this.loadUser() this.loadUser()
this.loadDatabase() this.loadDatabase()
.then(() => this.loadQuery())
.then(() => this.loadResult())
.then(() => this.loadMetadata()) .then(() => this.loadMetadata())
.then(() => {
this.simulateProgress()
this.loadQuery()
})
.then(() => this.loadResult())
}, },
methods: { methods: {
loadResult () { loadResult () {
...@@ -483,6 +503,20 @@ export default { ...@@ -483,6 +503,20 @@ export default {
this.downloadLoading = false this.downloadLoading = false
this.metadataLoading = false this.metadataLoading = false
}, },
simulateProgress () {
if (this.loadProgress !== 0) {
return
}
const timeout = 30 * 1000 /* ms */
const ticks = 100 /* ms */
let i = 0
setInterval(() => {
if (i++ >= timeout && !this.error) {
return
}
this.loadProgress = ((i * 100) / timeout) * 100
}, ticks)
},
async downloadData () { async downloadData () {
this.downloadLoading = true this.downloadLoading = true
try { try {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment