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

Last commit, deploy to the public instance

parent dfe3ac66
No related branches found
No related tags found
3 merge requests!81New stable release,!43Merge dev to master,!36Resolve "Test AMQP"
Showing
with 190 additions and 107 deletions
...@@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.*; ...@@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.security.Principal;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
......
package at.tuwien.repository.jpa;
import at.tuwien.entities.user.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
}
...@@ -4,9 +4,11 @@ import at.tuwien.api.identifier.IdentifierDto; ...@@ -4,9 +4,11 @@ import at.tuwien.api.identifier.IdentifierDto;
import at.tuwien.api.identifier.VisibilityTypeDto; import at.tuwien.api.identifier.VisibilityTypeDto;
import at.tuwien.entities.identifier.Identifier; import at.tuwien.entities.identifier.Identifier;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import org.bouncycastle.pqc.math.linearalgebra.PolynomialRingGF2;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.security.Principal;
import java.util.List; import java.util.List;
@Service @Service
...@@ -40,7 +42,9 @@ public interface IdentifierService { ...@@ -40,7 +42,9 @@ public interface IdentifierService {
* @return The created identifier from the metadata database if successful. * @return The created identifier from the metadata database if successful.
* @throws IdentifierPublishingNotAllowedException When the visibility is not self. * @throws IdentifierPublishingNotAllowedException When the visibility is not self.
*/ */
Identifier create(Long containerId, Long databaseId, IdentifierDto data) throws IdentifierPublishingNotAllowedException, QueryNotFoundException, RemoteUnavailableException, IdentifierAlreadyExistsException; Identifier create(Long containerId, Long databaseId, IdentifierDto data)
throws IdentifierPublishingNotAllowedException, QueryNotFoundException, RemoteUnavailableException,
IdentifierAlreadyExistsException;
/** /**
* Finds an identifier by given id in the metadata database. * Finds an identifier by given id in the metadata database.
......
...@@ -5,6 +5,7 @@ import at.tuwien.api.identifier.IdentifierDto; ...@@ -5,6 +5,7 @@ import at.tuwien.api.identifier.IdentifierDto;
import at.tuwien.api.identifier.VisibilityTypeDto; import at.tuwien.api.identifier.VisibilityTypeDto;
import at.tuwien.entities.identifier.Identifier; import at.tuwien.entities.identifier.Identifier;
import at.tuwien.entities.identifier.VisibilityType; import at.tuwien.entities.identifier.VisibilityType;
import at.tuwien.entities.user.User;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.gateway.QueryServiceGateway; import at.tuwien.gateway.QueryServiceGateway;
import at.tuwien.mapper.IdentifierMapper; import at.tuwien.mapper.IdentifierMapper;
...@@ -17,6 +18,7 @@ import org.springframework.dao.DataIntegrityViolationException; ...@@ -17,6 +18,7 @@ import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.security.Principal;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
......
...@@ -79,7 +79,7 @@ public class TableDataEndpoint { ...@@ -79,7 +79,7 @@ public class TableDataEndpoint {
.body(queryService.insert(id, databaseId, tableId, data)); .body(queryService.insert(id, databaseId, tableId, data));
} }
@GetMapping @RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD})
@Transactional(readOnly = true) @Transactional(readOnly = true)
@ApiOperation(value = "Get values", notes = "Get Data from a Table in the database.") @ApiOperation(value = "Get values", notes = "Get Data from a Table in the database.")
@ApiResponses({ @ApiResponses({
...@@ -116,28 +116,5 @@ public class TableDataEndpoint { ...@@ -116,28 +116,5 @@ public class TableDataEndpoint {
.body(response); .body(response);
} }
@RequestMapping(method = RequestMethod.HEAD)
@Transactional(readOnly = true)
@ApiOperation(value = "Get values", notes = "Get Data Count from a Table in the database.")
@ApiResponses({
@ApiResponse(code = 200, message = "Get data from the table."),
@ApiResponse(code = 401, message = "Not authorized to update tables."),
@ApiResponse(code = 404, message = "The table is not found in database."),
@ApiResponse(code = 405, message = "The connection to the database was unsuccessful."),
})
public ResponseEntity<QueryResultDto> getCount(@NotNull @PathVariable("id") Long id,
@NotNull @PathVariable("databaseId") Long databaseId,
@NotNull @PathVariable("tableId") Long tableId,
@RequestParam(required = false) Instant timestamp)
throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
TableMalformedException, ContainerNotFoundException {
final BigInteger count = queryService.count(id, databaseId, tableId, timestamp);
final HttpHeaders headers = new HttpHeaders();
headers.set("FDA-COUNT", count.toString());
return ResponseEntity.ok()
.headers(headers)
.build();
}
} }
...@@ -225,7 +225,7 @@ public interface QueryMapper { ...@@ -225,7 +225,7 @@ public interface QueryMapper {
if (data == null) { if (data == null) {
return null; return null;
} }
log.debug("map data {} to table column {}", data, column); log.trace("map data {} to table column {}", data, column);
switch (column.getColumnType()) { switch (column.getColumnType()) {
case BLOB: case BLOB:
log.trace("mapping {} to blob", data); log.trace("mapping {} to blob", data);
......
...@@ -93,9 +93,19 @@ export default { ...@@ -93,9 +93,19 @@ export default {
computed: { computed: {
loadingColor () { loadingColor () {
return this.error ? 'red lighten-2' : 'primary' return this.error ? 'red lighten-2' : 'primary'
},
token () {
return this.$store.state.token
},
headers () {
if (this.token === null) {
return null
}
return { Authorization: `Bearer ${this.token}` }
} }
}, },
beforeMount () { beforeMount () {
this.loadUser()
}, },
methods: { methods: {
cancel () { cancel () {
...@@ -107,11 +117,12 @@ export default { ...@@ -107,11 +117,12 @@ export default {
}) })
}, },
async persist () { async persist () {
console.debug('identifier data', this.identifier)
this.loading = true this.loading = true
let res let res
try { try {
res = await this.$axios.post(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/identifier`, this.identifier) res = await this.$axios.post(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/identifier`, this.identifier, {
headers: this.headers
})
console.debug('persist', res.data) console.debug('persist', res.data)
} catch (err) { } catch (err) {
this.$toast.error('Failed to persist query') this.$toast.error('Failed to persist query')
...@@ -119,6 +130,19 @@ export default { ...@@ -119,6 +130,19 @@ export default {
} }
this.$toast.success('Query persisted.') this.$toast.success('Query persisted.')
this.$emit('close') this.$emit('close')
},
async loadUser () {
this.loading = true
let res
try {
res = await this.$axios.put('/api/auth', null, {
headers: this.headers
})
console.debug('user data', res.data)
} catch (err) {
this.$toast.error('Failed load user data')
console.error('load user data failed', err)
}
} }
} }
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
</v-card-subtitle> </v-card-subtitle>
<v-card-text> <v-card-text>
<v-date-picker <v-date-picker
v-model="picker" v-model="date"
no-title /> no-title />
<v-time-picker <v-time-picker
v-model="time" v-model="time"
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
<v-btn <v-btn
id="version" id="version"
class="mb-2" class="mb-2"
:disabled="version === null || version === undefined" :disabled="date === null || time === null"
color="primary" color="primary"
@click="pick"> @click="pick">
Pick Pick
...@@ -50,8 +50,8 @@ export default { ...@@ -50,8 +50,8 @@ export default {
formValid: false, formValid: false,
loading: false, loading: false,
error: false, error: false,
version: null, date: null,
versions: [] time: null
} }
}, },
computed: { computed: {
...@@ -59,9 +59,6 @@ export default { ...@@ -59,9 +59,6 @@ export default {
return this.error ? 'red lighten-2' : 'primary' return this.error ? 'red lighten-2' : 'primary'
} }
}, },
mounted () {
this.loadVersions()
},
methods: { methods: {
cancel () { cancel () {
this.$parent.$parent.$parent.$parent.pickVersionDialog = false this.$parent.$parent.$parent.$parent.pickVersionDialog = false
...@@ -72,25 +69,19 @@ export default { ...@@ -72,25 +69,19 @@ export default {
}) })
}, },
reset () { reset () {
this.$parent.$parent.$parent.$parent.version = { id: null, created: null } this.$parent.$parent.$parent.$parent.version = null
this.cancel() this.cancel()
}, },
pick () { pick () {
this.$parent.$parent.$parent.$parent.version = this.versions[this.version] this.$parent.$parent.$parent.$parent.version = this.formatDate()
this.cancel() this.cancel()
}, },
async loadVersions () { formatDate () {
this.loading = true if (this.date === null || this.time === null) {
try { return null
const url = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/version`
const res = await this.$axios.get(url)
this.versions = res.data
console.debug('versions', this.versions)
} catch (err) {
console.error('Failed to get versions', err)
this.$toast.error('Failed to get versions')
} }
this.loading = false console.debug('selected date', this.date, 'time', this.time)
return Date.parse(this.date + ' ' + this.time)
} }
} }
} }
......
...@@ -8,10 +8,10 @@ ...@@ -8,10 +8,10 @@
<v-toolbar-title>Create Query</v-toolbar-title> <v-toolbar-title>Create Query</v-toolbar-title>
<v-spacer /> <v-spacer />
<v-toolbar-title> <v-toolbar-title>
<v-btn :disabled="!valid" color="blue-grey white--text" @click="save"> <v-btn :disabled="!valid || !token" color="blue-grey white--text" @click="save">
Save without execution Save without execution
</v-btn> </v-btn>
<v-btn :disabled="!valid" color="primary" @click="execute"> <v-btn :disabled="!valid || !token" color="primary" @click="execute">
<v-icon left>mdi-run</v-icon> <v-icon left>mdi-run</v-icon>
Execute Execute
</v-btn> </v-btn>
...@@ -115,6 +115,15 @@ export default { ...@@ -115,6 +115,15 @@ export default {
}, },
tableId () { tableId () {
return this.table.id return this.table.id
},
token () {
return this.$store.state.token
},
headers () {
if (this.token === null) {
return null
}
return { Authorization: `Bearer ${this.token}` }
} }
}, },
watch: { watch: {
...@@ -125,18 +134,21 @@ export default { ...@@ -125,18 +134,21 @@ export default {
} }
} }
}, },
async mounted () { beforeMount () {
// XXX same as in TableList this.loadTables()
},
methods: {
async loadTables () {
try { try {
const res = await this.$axios.get( const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.databaseId}/table`, {
`/api/container/${this.$route.params.container_id}/database/${this.databaseId}/table`) headers: this.headers
})
this.tables = res.data this.tables = res.data
console.debug('tables', this.tables) console.debug('tables', this.tables)
} catch (err) { } catch (err) {
this.$toast.error('Could not list table.') this.$toast.error('Could not list table.')
} }
}, },
methods: {
async execute () { async execute () {
this.$refs.form.validate() this.$refs.form.validate()
this.loading = true this.loading = true
...@@ -149,7 +161,9 @@ export default { ...@@ -149,7 +161,9 @@ export default {
})] })]
} }
console.debug('send data', data) console.debug('send data', data)
const res = await this.$axios.put(`/api/container/${this.$route.params.container_id}/database/${this.databaseId}/table/${this.tableId}/query/execute`, data) const res = await this.$axios.put(`/api/container/${this.$route.params.container_id}/database/${this.databaseId}/query/execute`, data, {
headers: this.headers
})
console.debug('query result', res) console.debug('query result', res)
this.$toast.success('Successfully executed query') this.$toast.success('Successfully executed query')
this.loading = false this.loading = false
...@@ -169,13 +183,14 @@ export default { ...@@ -169,13 +183,14 @@ export default {
const query = this.query.sql.replaceAll('`', '') const query = this.query.sql.replaceAll('`', '')
this.loading = true this.loading = true
try { try {
const res = await this.$axios.post(`/api/container/${this.$route.params.container_id}/database/${this.databaseId}/table/${this.tableId}/query/save`, { const res = await this.$axios.post(`/api/container/${this.$route.params.container_id}/database/${this.databaseId}/query/save`, { statement: query }, {
statement: query headers: this.headers
}) })
console.debug('query result', res) console.debug('query result', res)
this.$toast.success('Successfully saved query') this.$toast.success('Successfully saved query')
this.loading = false this.loading = false
this.queryId = res.data.id this.queryId = res.data.id
this.$router.push(`/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/query/${this.queryId}`)
} catch (err) { } catch (err) {
console.error('query save', err) console.error('query save', err)
this.$toast.error('Could not save query') this.$toast.error('Could not save query')
...@@ -204,7 +219,9 @@ export default { ...@@ -204,7 +219,9 @@ export default {
async loadColumns () { async loadColumns () {
const tableId = this.table.id const tableId = this.table.id
try { try {
const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.databaseId}/table/${tableId}`) const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.databaseId}/table/${tableId}`, {
headers: this.headers
})
this.tableDetails = res.data this.tableDetails = res.data
this.buildQuery() this.buildQuery()
} catch (err) { } catch (err) {
......
...@@ -4,23 +4,21 @@ ...@@ -4,23 +4,21 @@
<v-toolbar-title>{{ identifier.title }}</v-toolbar-title> <v-toolbar-title>{{ identifier.title }}</v-toolbar-title>
<v-spacer /> <v-spacer />
<v-toolbar-title> <v-toolbar-title>
<v-btn color="blue-grey white--text" class="mr-2" :disabled="!query.execution || identifier.id" @click.stop="persistQueryDialog = true"> <v-btn color="blue-grey white--text" class="mr-2" :disabled="!query.execution || identifier.id || !token" @click.stop="persistQueryDialog = true">
<v-icon left>mdi-fingerprint</v-icon> Persist <v-icon left>mdi-fingerprint</v-icon> Persist
</v-btn> </v-btn>
<v-btn color="primary" disabled> <v-btn color="primary" :disabled="!token">
<v-icon left>mdi-run</v-icon> Re-Execute <v-icon left>mdi-run</v-icon> Re-Execute
</v-btn> </v-btn>
</v-toolbar-title> </v-toolbar-title>
</v-toolbar> </v-toolbar>
<v-card flat> <v-card v-if="!loading" flat>
<v-card-title v-if="!loading"> <v-card-title>
<span v-if="query.execution != null"> Query Information
sha256:{{ query.query_hash }}
</span>
</v-card-title> </v-card-title>
<v-card-subtitle v-if="!loading"> <v-card-subtitle>
<span v-if="query.execution != null"> <span v-if="query.created != null">
Executed {{ formatDate(query.execution) }} Created {{ formatDate(query.created) }}
</span> </span>
<span v-if="query.execution == null"> <span v-if="query.execution == null">
Query was never executed Query was never executed
...@@ -31,9 +29,8 @@ ...@@ -31,9 +29,8 @@
<strong>Query</strong> <strong>Query</strong>
</p> </p>
<div> <div>
<p>Persistent Identifier</p> <p>
<p v-if="identifier.id"> Persistent Identifier: <code v-if="identifier.id">https://dbrepo.ossdip.at/pid/{{ identifier.id }}</code><span v-if="!identifier.id">(empty)</span>
<code>https://dbrepo.ossdip.at/pid/{{ identifier.id }}</code>
</p> </p>
<p>Statement</p> <p>Statement</p>
<v-alert <v-alert
...@@ -58,13 +55,23 @@ ...@@ -58,13 +55,23 @@
<strong>Result</strong> <strong>Result</strong>
</p> </p>
<p> <p>
Hash: <code>{{ query.result_hash }}</code> Hash: <code v-if="query.result_hash">{{ query.result_hash }}</code><span v-if="!query.result_hash">(empty)</span>
</p>
<p>
Rows: <code v-if="query.result_number">{{ query.result_number }}</code><span v-if="!query.result_number">(empty)</span>
</p>
<p>
Executed: <code v-if="query.execution">{{ query.execution }}</code><span v-if="!query.execution">(empty)</span>
</p>
<p class="mt-2">
<strong>Creator</strong>
</p> </p>
<p> <p>
Rows: <code>{{ query.result_number }}</code> Username: <code v-if="query.username">{{ query.username }}</code><span v-if="!query.username">(empty)</span>
</p> </p>
</v-card-text> </v-card-text>
</v-card> </v-card>
<v-breadcrumbs :items="items" class="pa-0 mt-2" />
<v-dialog <v-dialog
v-model="persistQueryDialog" v-model="persistQueryDialog"
persistent persistent
...@@ -84,6 +91,12 @@ export default { ...@@ -84,6 +91,12 @@ export default {
}, },
data () { data () {
return { return {
items: [
{ text: 'Databases', href: '/container' },
{ text: `${this.$route.params.database_id}`, href: `/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}` },
{ text: 'Queries', href: `/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/query` },
{ text: `${this.$route.params.query_id}`, href: `/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/query/${this.$route.params.query_id}` }
],
query: { query: {
id: this.$route.params.query_id, id: this.$route.params.query_id,
database_id: null, database_id: null,
...@@ -109,6 +122,17 @@ export default { ...@@ -109,6 +122,17 @@ export default {
loading: true loading: true
} }
}, },
computed: {
token () {
return this.$store.state.token
},
headers () {
if (this.token === null) {
return null
}
return { Authorization: `Bearer ${this.token}` }
}
},
mounted () { mounted () {
this.loadMetadata() this.loadMetadata()
}, },
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<v-toolbar :color="versionColor" flat> <v-toolbar :color="versionColor" flat>
<v-toolbar-title> <v-toolbar-title>
<strong>Versioning</strong> <strong>Versioning</strong>
<span v-if="version.id !== null">{{ version.created }}</span> <span v-if="version !== null">{{ versionFormatted }}</span>
</v-toolbar-title> </v-toolbar-title>
<v-spacer /> <v-spacer />
<v-toolbar-title> <v-toolbar-title>
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
</template> </template>
<script> <script>
import TimeTravel from '@/components/dialogs/TimeTravel' import TimeTravel from '@/components/dialogs/TimeTravel'
import { format } from 'date-fns'
export default { export default {
components: { components: {
...@@ -73,10 +74,7 @@ export default { ...@@ -73,10 +74,7 @@ export default {
dateMenu: false, dateMenu: false,
timeMenu: false, timeMenu: false,
pickVersionDialog: null, pickVersionDialog: null,
version: { version: null,
id: null,
created: null
},
options: { options: {
page: 1, page: 1,
itemsPerPage: 10 itemsPerPage: 10
...@@ -101,10 +99,16 @@ export default { ...@@ -101,10 +99,16 @@ export default {
}, },
versionColor () { versionColor () {
console.debug('version', this.version) console.debug('version', this.version)
if (this.version.created === null) { if (this.version === null) {
return 'grey lighten-1' return 'grey lighten-1'
} }
return 'primary white--text' return 'primary white--text'
},
versionFormatted () {
if (this.version === null) {
return null
}
return this.formatDate(this.version)
} }
}, },
watch: { watch: {
...@@ -139,9 +143,9 @@ export default { ...@@ -139,9 +143,9 @@ export default {
try { try {
this.loading = true this.loading = true
let url = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data?page=${this.options.page - 1}&size=${this.options.itemsPerPage}` let url = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data?page=${this.options.page - 1}&size=${this.options.itemsPerPage}`
if (this.version.created !== null) { if (this.version !== null) {
console.info('versioning active', this.version) console.info('versioning active', this.version)
url += `&timestamp=${this.version.created}` url += `&timestamp=${new Date(this.version).toISOString()}`
} }
const res = await this.$axios.get(url) const res = await this.$axios.get(url)
console.debug('version', this.datetime, 'table data', res.data) console.debug('version', this.datetime, 'table data', res.data)
...@@ -152,16 +156,17 @@ export default { ...@@ -152,16 +156,17 @@ export default {
} }
this.loading = false this.loading = false
}, },
async loadDataCount () { loadDataCount () { // TODO
try { // try {
this.loading = true // this.loading = true
const url = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data` // const url = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data`
const res = await this.$axios.head(url) // const res = await this.$axios.head(url)
console.debug('data count', res.data) // console.debug('data count', res.data)
this.total = res.data.count // this.total = res.data.count
} catch (err) { // } catch (err) {
console.error('failed to load total count', err) // console.error('failed to load total count', err)
} // }
this.total = 1000000
this.loading = false this.loading = false
}, },
columnAddition (column) { columnAddition (column) {
...@@ -172,6 +177,9 @@ export default { ...@@ -172,6 +177,9 @@ export default {
return '' return ''
} }
return '' return ''
},
formatDate (d) {
return format(new Date(d), 'dd.MM.yyyy HH:mm')
} }
} }
} }
......
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Description</th>
<th>Engine</th> <th>Engine</th>
<th>Tables</th>
<th>Created</th> <th>Created</th>
</tr> </tr>
</thead> </thead>
...@@ -31,15 +31,12 @@ ...@@ -31,15 +31,12 @@
</tr> </tr>
<tr <tr
v-for="item in databases" v-for="item in databases"
:key="item.id"> :key="item.id"
<td> class="database"
<v-btn :to="`/container/${item.container_id}/database/${item.id}/info`" icon> @click="loadDatabase(item)">
<v-icon>{{ iconSelect }}</v-icon> <td>{{ item.name }}</td>
</v-btn>
{{ item.name }}
</td>
<td>{{ item.description }}</td>
<td>{{ item.engine }}</td> <td>{{ item.engine }}</td>
<td></td>
<td>{{ formatDate(item.created) }}</td> <td>{{ formatDate(item.created) }}</td>
</tr> </tr>
</tbody> </tbody>
...@@ -107,6 +104,9 @@ export default { ...@@ -107,6 +104,9 @@ export default {
this.error = true this.error = true
} }
}, },
loadDatabase (database) {
this.$router.push(`/container/${database.container_id}/database/${database.id}/info`)
},
trim (s) { trim (s) {
return s.slice(0, 12) return s.slice(0, 12)
}, },
...@@ -131,6 +131,9 @@ export default { ...@@ -131,6 +131,9 @@ export default {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.database:hover {
cursor: pointer;
}
.color-grey { .color-grey {
color: #aaa; color: #aaa;
} }
......
<template> <template>
<div /> <div>
<v-card>
<v-card-title>PID Not Found</v-card-title>
<v-card-subtitle>{{ pid }}</v-card-subtitle>
<v-card-text>
<p>This PID cannot be found in the system. Possible reasons are:</p>
<ul>
<li>The PID is incorrect in your source.</li>
<li>The PID was copied incorrectly.</li>
<li>The PID has not been activated yet.</li>
</ul>
</v-card-text>
</v-card>
</div>
</template> </template>
<script> <script>
...@@ -7,6 +20,11 @@ export default { ...@@ -7,6 +20,11 @@ export default {
mounted () { mounted () {
this.findPid() this.findPid()
}, },
computed: {
pid () {
return this.$route.params.pid_id
}
},
methods: { methods: {
async findPid () { async findPid () {
try { try {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment