Skip to content
Snippets Groups Projects
Verified Commit d296ae5a authored by Kotyba Alhaj Taha's avatar Kotyba Alhaj Taha
Browse files

Change platform pages:

- remove old id page
- Add new platform sites
parent 1e93ee63
No related branches found
No related tags found
2 merge requests!92Feature restructure frontend platforms,!82Restructure frontend
<!--
Web client of the Sensor Management System software developed within the
Helmholtz DataHub Initiative by GFZ and UFZ.
Copyright (C) 2020
- Nils Brinckmann (GFZ, nils.brinckmann@gfz-potsdam.de)
- Marc Hanisch (GFZ, marc.hanisch@gfz-potsdam.de)
- Helmholtz Centre Potsdam - GFZ German Research Centre for
Geosciences (GFZ, https://www.gfz-potsdam.de)
Parts of this program were developed within the context of the
following publicly funded projects or measures:
- Helmholtz Earth and Environment DataHub
(https://www.helmholtz.de/en/research/earth_and_environment/initiatives/#h51095)
Licensed under the HEESIL, Version 1.0 or - as soon they will be
approved by the "Community" - subsequent versions of the HEESIL
(the "Licence").
You may not use this work except in compliance with the Licence.
You may obtain a copy of the Licence at:
https://gitext.gfz-potsdam.de/software/heesil
Unless required by applicable law or agreed to in writing, software
distributed under the Licence is distributed on an "AS IS" basis,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the Licence for the specific language governing
permissions and limitations under the Licence.
-->
<template>
<div>
<v-card outlined>
<v-tabs-items
v-model="activeTab"
>
<v-tab-item :eager="true">
<v-form ref="basicForm">
<!-- Basic data tab -->
<v-card
flat
>
<v-card-title>
Platform URN: {{ platformURN }}
</v-card-title>
<v-card-text>
<v-row>
<v-col cols="12" md="3">
<v-text-field
v-model="platform.persistentIdentifier"
label="Persistent identifier (PID)"
:readonly="readonly"
:disabled="readonly"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="platform.shortName"
label="Short name"
required
class="required"
:rules="[rules.required]"
:readonly="readonly"
:disabled="readonly"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field v-model="platform.longName" label="Long name" :readonly="readonly" :disabled="readonly" />
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="3">
<v-combobox
v-model="platformStatusName"
label="Status"
:items="statusNames"
:readonly="readonly"
:disabled="readonly"
/>
</v-col>
<v-col cols="12" md="3">
<v-combobox
v-model="platformPlatformTypeName"
label="Platform type"
:items="platformTypeNames"
:readonly="readonly"
:disabled="readonly"
/>
</v-col>
<v-col cols="12" md="3">
<v-combobox
v-model="platformManufacturerName"
label="Manufacturer"
:items="manufacturerNames"
:readonly="readonly"
:disabled="readonly"
/>
</v-col>
<v-col cols="12" md="3">
<v-text-field
v-model="platform.model"
label="Model"
:readonly="readonly"
:disabled="readonly"
/>
</v-col>
</v-row>
<v-divider />
<v-row>
<v-col cols="12" md="9">
<v-textarea v-model="platform.description" label="Description" rows="3" :readonly="readonly" :disabled="readonly" />
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="9">
<v-text-field
v-if="readonly"
v-model="platform.website"
label="Website"
placeholder="https://"
type="url"
:readonly="true"
:disabled="true"
>
<template slot="append">
<a v-if="platform.website.length > 0" :href="platform.website" target="_blank">
<v-icon>
mdi-open-in-new
</v-icon>
</a>
</template>
</v-text-field>
<v-text-field
v-else
v-model="platform.website"
label="Website"
placeholder="https://"
type="url"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="3">
<v-text-field
v-model="platform.serialNumber"
label="Serial number"
:readonly="readonly"
:disabled="readonly"
/>
</v-col>
<v-col cols="12" md="3">
<v-text-field v-model="platform.inventoryNumber" label="Inventory number" :readonly="readonly" :disabled="readonly" />
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-form>
</v-tab-item>
<!-- contact tab -->
<v-tab-item :eager="true">
<v-form ref="contactsForm" @submit.prevent>
<v-card
flat
>
<v-card-title>
Platform URN: {{ platformURN }}
</v-card-title>
<v-card-text>
<v-row>
<v-col cols="3">
<ContactSelect v-model="platform.contacts" :readonly="!editMode" label="Add a contact" />
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-form>
</v-tab-item>
<v-tab-item :eager="true">
<v-card
flat
>
<v-card-title>
Platform URN: {{ platformURN }}
</v-card-title>
<v-card-text>
<AttachmentList v-model="platform.attachments" :readonly="!editMode" />
</v-card-text>
</v-card>
</v-tab-item>
</v-tabs-items>
<!-- Buttons for all tabs -->
<v-btn
v-if="!editMode && isLoggedIn"
fab
fixed
bottom
right
color="secondary"
@click="onEditButtonClick"
>
<v-icon>
mdi-pencil
</v-icon>
</v-btn>
</v-card>
</div>
</template>
<style lang="scss">
@import "@/assets/styles/_forms.scss";
</style>
<script lang="ts">
import { Component, Watch, mixins } from 'nuxt-property-decorator'
import { Rules } from '@/mixins/Rules'
import AttachmentList from '@/components/AttachmentList.vue'
import ContactSelect from '@/components/ContactSelect.vue'
import { Manufacturer } from '@/models/Manufacturer'
import { Platform } from '@/models/Platform'
import { PlatformType } from '@/models/PlatformType'
import { Status } from '@/models/Status'
@Component({
components: {
ContactSelect,
AttachmentList
}
})
// @ts-ignore
export default class PlatformIdPage extends mixins(Rules) {
// data
// first for the data to chose the elements
private platformTypes: PlatformType[] = []
private manufacturers: Manufacturer[] = []
private states: Status[] = []
// then for our platform that we want to change
private platform: Platform = Platform.createEmpty()
private platformBackup: Platform | null = null
// and some general data for the page
private editMode: boolean = false
created () {
this.initializeAppBar()
this.registerButtonActions()
}
mounted () {
this.$api.manufacturer.findAllPaginated().then((foundManufacturers) => {
this.manufacturers = foundManufacturers
}).catch(() => {
this.$store.commit('snackbar/setError', 'Loading of manufactures failed')
})
this.$api.platformTypes.findAllPaginated().then((foundPlatformTypes) => {
this.platformTypes = foundPlatformTypes
}).catch(() => {
this.$store.commit('snackbar/setError', 'Loading of platform types failed')
})
this.$api.states.findAllPaginated().then((foundStates) => {
this.states = foundStates
}).catch(() => {
this.$store.commit('snackbar/setError', 'Loading of states failed')
})
this.loadPlatform().then((platform) => {
if (platform === null) {
this.$store.commit('appbar/setTitle', 'Add Platform')
}
}).catch(() => {
this.$store.commit('snackbar/setError', 'Loading platform failed')
})
}
beforeDestroy () {
this.unregisterButtonActions()
this.$store.dispatch('appbar/setDefaults')
}
registerButtonActions () {
this.$nuxt.$on('AppBarEditModeContent:save-btn-click', () => {
this.save().then(() => {
this.$store.commit('snackbar/setSuccess', 'Save successful')
}).catch(() => {
this.$store.commit('snackbar/setError', 'Save failed')
})
})
this.$nuxt.$on('AppBarEditModeContent:cancel-btn-click', () => {
this.cancel()
})
}
unregisterButtonActions () {
this.$nuxt.$off('AppBarEditModeContent:save-btn-click')
this.$nuxt.$off('AppBarEditModeContent:cancel-btn-click')
}
initializeAppBar () {
this.$store.dispatch('appbar/init', {
tabs: [
'Basic Data',
'Contacts',
'Attachments'
],
title: 'Platforms',
saveBtnHidden: true,
cancelBtnHidden: true
})
}
get activeTab (): number | null {
return this.$store.state.appbar.activeTab
}
set activeTab (tab: number | null) {
this.$store.commit('appbar/setActiveTab', tab)
}
loadPlatform (): Promise<Platform|null> {
return new Promise((resolve, reject) => {
const platformId = this.$route.params.id
if (!platformId) {
this.createBackup()
this.editMode = true && this.isLoggedIn
resolve(null)
return
}
this.editMode = false
this.$api.platforms.findById(platformId).then((foundPlatform) => {
this.platform = foundPlatform
resolve(foundPlatform)
}).catch((_error) => {
reject(_error)
})
})
}
createBackup () {
this.platformBackup = Platform.createFromObject(this.platform)
}
restoreBackup () {
if (!this.platformBackup) {
return
}
this.platform = this.platformBackup
this.platformBackup = null
}
// methods
save (): Promise<Platform|null> {
return new Promise((resolve, reject) => {
this.$api.platforms.save(this.platform).then((savedPlatform) => {
this.platform = savedPlatform
this.platformBackup = null
this.editMode = false
resolve(savedPlatform)
}).catch((_error) => {
reject(_error)
})
})
}
cancel () {
this.restoreBackup()
if (this.platform.id) {
this.editMode = false
} else {
this.$router.push('/search/platforms')
}
}
onEditButtonClick () {
this.createBackup()
this.editMode = true && this.isLoggedIn
}
get platformURN () {
// return the current platform urn to display it in the form
const removeWhitespace = (text: string) => {
return text.replace(' ', '_')
}
let partPlatformType = '[platformtype]'
if (this.platform.platformTypeUri !== '') {
const ptIndex = this.platformTypes.findIndex(pt => pt.uri === this.platform.platformTypeUri)
if (ptIndex > -1) {
partPlatformType = this.platformTypes[ptIndex].name
}
}
let partShortName = '[short_name]'
if (this.platform.shortName !== '') {
partShortName = removeWhitespace(this.platform.shortName)
}
return partPlatformType + '_' + partShortName
}
get readonly () {
return !this.editMode
}
get manufacturerNames () : string[] {
return this.manufacturers.map(m => m.name)
}
get platformManufacturerName (): string {
const manufacturerIndex = this.manufacturers.findIndex(m => m.uri === this.platform.manufacturerUri)
if (manufacturerIndex > -1) {
return this.manufacturers[manufacturerIndex].name
}
return this.platform.manufacturerName
}
set platformManufacturerName (newName: string) {
this.platform.manufacturerName = newName
const manufacturerIndex = this.manufacturers.findIndex(m => m.name === newName)
if (manufacturerIndex > -1) {
this.platform.manufacturerUri = this.manufacturers[manufacturerIndex].uri
} else {
this.platform.manufacturerUri = ''
}
}
get statusNames () : string[] {
return this.states.map(s => s.name)
}
get platformStatusName (): string {
const statusIndex = this.states.findIndex(s => s.uri === this.platform.statusUri)
if (statusIndex > -1) {
return this.states[statusIndex].name
}
return this.platform.statusName
}
set platformStatusName (newName: string) {
this.platform.statusName = newName
const statusIndex = this.states.findIndex(s => s.name === newName)
if (statusIndex > -1) {
this.platform.statusUri = this.states[statusIndex].uri
} else {
this.platform.statusUri = ''
}
}
get platformTypeNames () : string[] {
return this.platformTypes.map(t => t.name)
}
get platformPlatformTypeName () : string {
const platformTypeIndex = this.platformTypes.findIndex(t => t.uri === this.platform.platformTypeUri)
if (platformTypeIndex > -1) {
return this.platformTypes[platformTypeIndex].name
}
return this.platform.platformTypeName
}
set platformPlatformTypeName (newName: string) {
this.platform.platformTypeName = newName
const platformTypeIndex = this.platformTypes.findIndex(t => t.name === newName)
if (platformTypeIndex > -1) {
this.platform.platformTypeUri = this.platformTypes[platformTypeIndex].uri
} else {
this.platform.platformTypeUri = ''
}
}
@Watch('platform', { immediate: true, deep: true })
// @ts-ignore
onPlatformChanged (val: Platform) {
if (val.id) {
this.$store.commit('appbar/setTitle', val?.shortName || 'Add Platform')
}
}
@Watch('editMode', { immediate: true, deep: true })
// @ts-ignore
onEditModeChanged (editMode: boolean) {
this.$store.commit('appbar/setSaveBtnHidden', !editMode)
this.$store.commit('appbar/setCancelBtnHidden', !editMode)
}
get isLoggedIn () {
return this.$store.getters['oidc/isAuthenticated']
}
}
</script>
<!--
Web client of the Sensor Management System software developed within the
Helmholtz DataHub Initiative by GFZ and UFZ.
Copyright (C) 2020
- Nils Brinckmann (GFZ, nils.brinckmann@gfz-potsdam.de)
- Marc Hanisch (GFZ, marc.hanisch@gfz-potsdam.de)
- Helmholtz Centre Potsdam - GFZ German Research Centre for
Geosciences (GFZ, https://www.gfz-potsdam.de)
Parts of this program were developed within the context of the
following publicly funded projects or measures:
- Helmholtz Earth and Environment DataHub
(https://www.helmholtz.de/en/research/earth_and_environment/initiatives/#h51095)
Licensed under the HEESIL, Version 1.0 or - as soon they will be
approved by the "Community" - subsequent versions of the HEESIL
(the "Licence").
You may not use this work except in compliance with the Licence.
You may obtain a copy of the Licence at:
https://gitext.gfz-potsdam.de/software/heesil
Unless required by applicable law or agreed to in writing, software
distributed under the Licence is distributed on an "AS IS" basis,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the Licence for the specific language governing
permissions and limitations under the Licence.
-->
<template>
<div>
<ProgressIndicator
v-model="isLoading"
/>
<v-card flat>
<NuxtChild
v-model="platform"
/>
</v-card>
</div>
</template>
<script lang="ts">
import { Component, Vue, Watch } from 'nuxt-property-decorator'
import { Platform } from '@/models/Platform'
import ProgressIndicator from '@/components/ProgressIndicator.vue'
@Component({
components: {
ProgressIndicator
}
})
export default class PlatformPage extends Vue {
private platform: Platform = new Platform()
private isLoading: boolean = true
created () {
if (this.isBasePath()) {
this.$router.push('/platforms/' + this.platformId + '/basic')
}
}
mounted () {
this.initializeAppBar()
this.$api.platforms.findById(this.platformId).then((platform) => {
this.platform = platform
this.isLoading = false
}).catch((_error) => {
this.$store.commit('snackbar/setError', 'Loading platform failed')
this.isLoading = false
})
}
beforeDestroy () {
this.$store.dispatch('appbar/setDefaults')
}
initializeAppBar () {
this.$store.dispatch('appbar/init', {
tabs: [
{
to: '/platforms/' + this.platformId + '/basic',
name: 'Basic Data'
},
{
to: '/platforms/' + this.platformId + '/contacts',
name: 'Contacts'
},
{
to: '/platforms/' + this.platformId + '/attachments',
name: 'Attachments'
}
],
title: 'Platforms'
})
}
isBasePath () {
return this.$route.path === '/platforms/' + this.platformId || this.$route.path === '/platforms/' + this.platformId + '/'
}
get platformId () {
return this.$route.params.platformId
}
@Watch('platform', { immediate: true, deep: true })
// @ts-ignore
onPlatformChanged (val: Platform) {
if (val.id) {
this.$store.commit('appbar/setTitle', val?.shortName || 'Add Platform')
}
}
}
</script>
<template>
<div>
<ProgressIndicator
v-model="isInProgress"
:dark="isSaving"
/>
<v-card-actions>
<v-spacer />
<v-btn
v-if="isLoggedIn && !(isAddAttachmentPage)"
color="primary"
small
:disabled="isEditAttachmentPage"
:to="'/platforms/' + platformId + '/attachments/new'"
>
Add Attachment
</v-btn>
</v-card-actions>
<template v-if="isAddAttachmentPage">
<v-card class="mb-2">
<NuxtChild @showsave="showsave" @input="addAttachmentToList" />
</v-card>
</template>
<template
v-for="(attachment, index) in attachments"
>
<template v-if="isLoggedIn && isEditModeForAttachment(attachment)">
<NuxtChild
:key="attachment.id"
v-model="attachments[index]"
@showsave="showsave"
/>
</template>
<v-card v-else :key="attachment.id" class="mb-2">
<v-list-item>
<v-list-item-avatar>
<v-icon large>
{{ filetypeIcon(attachment) }}
</v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-subtitle>
{{ filename(attachment) }}, uploaded at {{ uploadedDateTime(attachment) }}
</v-list-item-subtitle>
<v-list-item-title>
<a :href="attachment.url" target="_blank">{{ attachment.label }}</a>
</v-list-item-title>
<v-list-item-action-text>
<v-row>
<v-col align-self="end" class="text-right">
<v-btn
v-if="isLoggedIn && !isEditAttachmentPage && !isAddAttachmentPage"
color="primary"
text
small
nuxt
:to="'/platforms/' + platformId + '/attachments/' + attachment.id + '/edit'"
>
Edit
</v-btn>
<v-menu
v-if="isLoggedIn"
close-on-click
close-on-content-click
offset-x
left
z-index="999"
>
<template v-slot:activator="{ on }">
<v-btn
data-role="property-menu"
icon
small
v-on="on"
>
<v-icon
dense
small
>
mdi-dots-vertical
</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
v-if="isLoggedIn && !isAddAttachmentPage && !isEditAttachmentPage"
dense
@click="showDeleteDialogFor(attachment.id)"
>
<v-list-item-content>
<v-list-item-title
class="red--text"
>
<v-icon
left
small
color="red"
>
mdi-delete
</v-icon>
Delete
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>
</v-col>
</v-row>
</v-list-item-action-text>
</v-list-item-content>
</v-list-item>
<v-dialog v-model="showDeleteDialog[attachment.id]" max-width="290">
<v-card>
<v-card-title class="headline">
Delete Attachment
</v-card-title>
<v-card-text>
Do you really want to delete the attachment <em>{{ attachment.label }}</em>?
</v-card-text>
<v-card-actions>
<v-btn
text
@click="hideDeleteDialogFor(attachment.id)"
>
No
</v-btn>
<v-spacer />
<v-btn
color="error"
text
@click="deleteAndCloseDialog(attachment.id)"
>
<v-icon left>
mdi-delete
</v-icon>
Delete
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-card>
</template>
<v-card-actions
v-if="attachments.length > 3"
>
<v-spacer />
<v-btn
v-if="isLoggedIn"
color="primary"
small
:disabled="isEditAttachmentPage || isAddAttachmentPage"
>
Add Attachment
</v-btn>
</v-card-actions>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import { Attachment } from '@/models/Attachment'
import AttachmentListItem from '@/components/AttachmentListItem.vue'
import ProgressIndicator from '@/components/ProgressIndicator.vue'
@Component({
components: {
AttachmentListItem,
ProgressIndicator
}
})
export default class PlatformAttachmentsPage extends Vue {
private attachments: Attachment[] = []
private showDeleteDialog: {[idx: string]: boolean} = {}
private isLoading = false
private isSaving = false
async fetch () {
this.isLoading = true
try {
this.attachments = await this.$api.platforms.findRelatedPlatformAttachments(this.platformId)
this.isLoading = false
} catch (e) {
this.$store.commit('snackbar/setError', 'failed to fetch attachments')
this.isLoading = false
}
}
get isInProgress (): boolean {
return this.isLoading || this.isSaving
}
get platformId (): string {
return this.$route.params.platformId
}
get isLoggedIn (): boolean {
return this.$store.getters['oidc/isAuthenticated']
}
get isEditAttachmentPage (): boolean {
// eslint-disable-next-line no-useless-escape
const editUrl = '^\/platforms\/' + this.platformId + '\/attachments\/([0-9]+)\/edit$'
return !!this.$route.path.match(editUrl)
}
get isAddAttachmentPage (): boolean {
// eslint-disable-next-line no-useless-escape
const addUrl = '^\/platforms\/' + this.platformId + '\/attachments\/new$'
return !!this.$route.path.match(addUrl)
}
showsave (shouldShowSave: boolean) {
this.isSaving = shouldShowSave
}
addAttachmentToList (newAttachment: Attachment) {
this.attachments.push(newAttachment)
}
deleteAndCloseDialog (id: string) {
if (id) {
this.isSaving = true
this.showDeleteDialog = {}
this.$api.platformAttachments.deleteById(id).then(() => {
const searchIndex = this.attachments.findIndex(a => a.id === id)
if (searchIndex > -1) {
this.attachments.splice(searchIndex, 1)
}
this.isSaving = false
}).catch((_error) => {
this.isSaving = false
this.$store.commit('snackbar/setError', 'Failed to delete attachment')
})
}
}
showDeleteDialogFor (id: string) {
Vue.set(this.showDeleteDialog, id, true)
}
hideDeleteDialogFor (id: string) {
Vue.set(this.showDeleteDialog, id, false)
}
isEditModeForAttachment (attachment: Attachment): boolean {
return this.$route.path === '/platforms/' + this.platformId + '/attachments/' + attachment.id + '/edit'
}
/**
* returns a filename from a full filepath
*
* @return {string} the filename
*/
filename (attachment: Attachment): string {
const UNKNOWN_FILENAME = 'unknown filename'
if (attachment.url === '') {
return UNKNOWN_FILENAME
}
const paths = attachment.url.split('/')
if (!paths.length) {
return UNKNOWN_FILENAME
}
// @ts-ignore
return paths.pop()
}
/**
* returns the timestamp of the upload date
*
* @TODO this must be implemented when the file API is ready
* @return {string} a readable timestamp
*/
uploadedDateTime (_attachment: Attachment): string {
return '2020-06-17 16:35 (TODO)'
}
/**
* returns a material design icon name based on the file type extension
*
* @return {string} a material design icon name
*/
filetypeIcon (attachment: Attachment): string {
let extension = ''
const paths = this.filename(attachment).split('.')
if (paths.length) {
// @ts-ignore
extension = paths.pop().toLowerCase()
}
switch (extension) {
case 'png':
case 'jpg':
case 'jpeg':
return 'mdi-image'
case 'pdf':
return 'mdi-file-pdf-box'
case 'doc':
case 'docx':
case 'odt':
return 'mdi-text-box'
default:
return 'mdi-paperclip'
}
}
}
</script>
<template>
<v-card class="mb-2">
<v-list-item>
<v-list-item-avatar>
<v-icon large>
{{ filetypeIcon }}
</v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-subtitle>
{{ filename }}, uploaded at {{ uploadedDateTime }}
</v-list-item-subtitle>
<v-list-item-title>
<v-text-field
v-model="valueCopy.label"
/>
</v-list-item-title>
</v-list-item-content>
<v-list-item-action-text>
<v-row>
<v-col align-self="end" class="text-right">
<v-btn
icon
color="primary"
:href="valueCopy.url"
target="_blank"
>
<v-icon>
mdi-open-in-new
</v-icon>
</v-btn>
<v-btn
ref="cancelButton"
text
small
:to="'/platforms/' + platformId + '/attachments'"
>
Cancel
</v-btn>
<v-btn
color="green"
small
@click.prevent.stop="save"
>
Apply
</v-btn>
</v-col>
</v-row>
</v-list-item-action-text>
</v-list-item>
</v-card>
</template>
<script lang="ts">
import { Vue, Component, Prop } from 'nuxt-property-decorator'
import { Attachment } from '@/models/Attachment'
/**
* A class component that displays a single attached file
* @extends Vue
*/
@Component
// @ts-ignore
export default class AttachmentEditPage extends Vue {
private valueCopy: Attachment = new Attachment()
/**
* an Attachment
*/
@Prop({
required: true,
type: Attachment
})
// @ts-ignore
readonly value!: Attachment
created () {
this.valueCopy = Attachment.createFromObject(this.value)
}
mounted () {
const cancelButton = this.$refs.cancelButton as Vue
// due to the active route (and the button being a router link)
// this button has the active class
// however, we don't want this special behaviour for this button
cancelButton.$el.classList.remove('v-btn--active')
}
get platformId (): string {
return this.$route.params.platformId
}
/**
* returns the timestamp of the upload date
*
* @TODO this must be implemented when the file API is ready
* @return {string} a readable timestamp
*/
get uploadedDateTime (): string {
return '2020-06-17 16:35 (TODO)'
}
/**
* returns a filename from a full filepath
*
* @return {string} the filename
*/
get filename (): string {
const UNKNOWN_FILENAME = 'unknown filename'
if (this.valueCopy.url === '') {
return UNKNOWN_FILENAME
}
const paths = this.valueCopy.url.split('/')
if (!paths.length) {
return UNKNOWN_FILENAME
}
// @ts-ignore
return paths.pop()
}
save () {
this.$emit('showsave', true)
this.$api.platformAttachments.update(this.platformId, this.valueCopy).then((savedAttachment: Attachment) => {
this.$emit('showsave', false)
this.$emit('input', savedAttachment)
this.$router.push('/platforms/' + this.platformId + '/attachments')
}).catch(() => {
this.$emit('showsave', false)
this.$store.commit('snackbar/setError', 'Failed to save an attachment')
})
}
}
</script>
<template>
<v-form ref="attachmentsForm" class="pl-10" @submit.prevent>
<v-row>
<v-col cols="12" md="3">
<v-radio-group
v-model="attachmentType"
label="Type"
row
>
<v-radio label="File" value="file" />
<v-radio label="Url" value="url" />
</v-radio-group>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="4">
<v-file-input
v-if="attachmentType === 'file'"
v-model="file"
:accept="mimeTypeList"
label="File"
required
class="required"
:rules="[rules.required]"
show-size
/>
<v-text-field
v-if="attachmentType === 'url'"
v-model="attachment.url"
label="URL"
type="url"
placeholder="http://"
required
class="required"
:rules="[rules.required, rules.validUrl]"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="4">
<v-text-field
v-model="attachment.label"
label="Label"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-spacer />
<v-btn
v-if="isLoggedIn"
ref="cancelButton"
text
small
:to="'/platforms/' + platformId + '/attachments'"
>
Cancel
</v-btn>
<v-btn
v-if="isLoggedIn"
color="green"
small
data-role="add-attachment"
@click="add()"
>
{{ attachmentType === 'url' ? 'Add' : 'Upload' }}
</v-btn>
</v-col>
</v-row>
</v-form>
</template>
<script lang="ts">
import { Component, mixins } from 'nuxt-property-decorator'
import { Rules } from '@/mixins/Rules'
import { Attachment } from '@/models/Attachment'
@Component({
components: {}
})
export default class AttachmentAddPage extends mixins(Rules) {
private attachment: Attachment = new Attachment()
private attachmentType: string = 'file'
private file: File | null = null
mounted () {
const cancelButton = this.$refs.cancelButton as Vue
// due to the active route (and the button being a router link)
// this button has the active class
// however, we don't want this special behaviour for this button
cancelButton.$el.classList.remove('v-btn--active')
}
/**
* returns a list of MimeTypes, seperated by ,
*
* @return {string} a list of MimeTypes
*/
get mimeTypeList (): string {
return Object.keys(Attachment.mimeTypes).join(',')
}
add () {
if (!(this.$refs.attachmentsForm as Vue & { validate: () => boolean }).validate()) {
return
}
(this.$refs.attachmentsForm as Vue & { resetValidation: () => boolean }).resetValidation()
this.$emit('showsave', true)
this.$api.platformAttachments.add(this.platformId, this.attachment).then((newAttachment: Attachment) => {
this.$emit('showsave', false)
this.$emit('input', newAttachment)
this.$router.push('/platforms/' + this.platformId + '/attachments')
}).catch(() => {
this.$emit('showsave', false)
this.$store.commit('snackbar/setError', 'Failed to save measured quantity')
})
}
get platformId (): string {
return this.$route.params.platformId
}
get isLoggedIn (): boolean {
return this.$store.getters['oidc/isAuthenticated']
}
}
</script>
<template>
<NuxtChild
v-model="platform"
/>
</template>
<script lang="ts">
import { Component, Vue, Prop } from 'nuxt-property-decorator'
import { Platform } from '@/models/Platform'
@Component
export default class PlatformBasicPage extends Vue {
@Prop({
required: true,
type: Object
})
readonly value!: Platform
get platform (): Platform {
return this.value
}
set platform (value: Platform) {
this.$emit('input', value)
}
}
</script>
<template>
<div>
<ProgressIndicator
v-model="isLoading"
dark
/>
<v-card-actions>
<v-spacer />
<v-btn
v-if="isLoggedIn"
small
text
nuxt
:to="'/platforms/' + platformId + '/basic'"
>
cancel
</v-btn>
<v-btn
v-if="isLoggedIn"
color="green"
small
@click="onSaveButtonClicked"
>
apply
</v-btn>
</v-card-actions>
<PlatformBasicDataForm
ref="basicForm"
v-model="platformCopy"
/>
<v-card-actions>
<v-spacer />
<v-btn
v-if="isLoggedIn"
small
text
nuxt
:to="'/platforms/' + platformId + '/basic'"
>
cancel
</v-btn>
<v-btn
v-if="isLoggedIn"
color="green"
small
@click="onSaveButtonClicked"
>
apply
</v-btn>
</v-card-actions>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Watch } from 'nuxt-property-decorator'
import PlatformBasicDataForm from '@/components/PlatformBasicDataForm.vue'
import ProgressIndicator from '@/components/ProgressIndicator.vue'
import { Platform } from '@/models/Platform'
@Component({
components: {
PlatformBasicDataForm,
ProgressIndicator
}
})
export default class PlatformEditBasicPage extends Vue {
// we need to initialize the instance variable with an empty Platform instance
// here, otherwise the form is not reactive
private platformCopy: Platform = new Platform()
private isLoading: boolean = false
@Prop({
required: true,
type: Object
})
readonly value!: Platform
created () {
this.platformCopy = Platform.createFromObject(this.value)
}
onSaveButtonClicked () {
if (!(this.$refs.basicForm as Vue & { validateForm: () => boolean }).validateForm()) {
this.$store.commit('snackbar/setError', 'Please correct your input')
return
}
this.isLoading = true
this.save().then((platform) => {
this.isLoading = false
this.$emit('input', platform)
this.$router.push('/platforms/' + this.platformId + '/basic')
}).catch((_error) => {
this.isLoading = false
this.$store.commit('snackbar/setError', 'Save failed')
})
}
save (): Promise<Platform> {
return new Promise((resolve, reject) => {
this.$api.platforms.save(this.platformCopy).then((savedPlatform) => {
resolve(savedPlatform)
}).catch((_error) => {
reject(_error)
})
})
}
get platformId () {
return this.$route.params.platformId
}
get isLoggedIn () {
return this.$store.getters['oidc/isAuthenticated']
}
@Watch('value', { immediate: true, deep: true })
// @ts-ignore
onPlatformChanged (val: Platform) {
this.platformCopy = Platform.createFromObject(val)
}
}
</script>
<template>
<div>
<v-card-actions>
<v-spacer />
<v-btn
v-if="isLoggedIn"
color="primary"
small
nuxt
:to="'/platforms/' + platformId + '/basic/edit'"
>
Edit
</v-btn>
</v-card-actions>
<PlatformBasicData
v-model="platform"
/>
<v-card-actions>
<v-spacer />
<v-btn
v-if="isLoggedIn"
color="primary"
small
nuxt
:to="'/platforms/' + platformId + '/basic/edit'"
>
Edit
</v-btn>
</v-card-actions>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'nuxt-property-decorator'
import { Platform } from '@/models/Platform'
import PlatformBasicData from '@/components/PlatformBasicData.vue'
@Component({
components: {
PlatformBasicData
}
})
export default class PlatformShowBasicPage extends Vue {
@Prop({
required: true,
type: Object
})
readonly value!: Platform
get platform (): Platform {
return this.value
}
set platform (value: Platform) {
this.$emit('input', value)
}
get platformId () {
return this.$route.params.platformId
}
get isLoggedIn () {
return this.$store.getters['oidc/isAuthenticated']
}
}
</script>
<template>
<div>
<ProgressIndicator
v-model="isInProgress"
:dark="isSaving"
/>
<NuxtChild
v-model="contacts"
/>
<v-card-actions
v-if="!isAddContactPage"
>
<v-spacer />
<v-btn
v-if="isLoggedIn"
color="primary"
small
nuxt
:to="'/platforms/' + platformId + '/contacts/new'"
>
Add contact
</v-btn>
</v-card-actions>
<v-expansion-panels>
<v-expansion-panel
v-for="contact in contacts"
:key="contact.id"
>
<v-expansion-panel-header>
<v-row
no-gutters
>
<v-col class="text-subtitle-1">
{{ contact.toString() }}
</v-col>
<v-col
align-self="end"
class="text-right"
>
<v-menu
v-if="isLoggedIn"
close-on-click
close-on-content-click
offset-x
left
z-index="999"
>
<template v-slot:activator="{ on }">
<v-btn
data-role="property-menu"
icon
small
v-on="on"
>
<v-icon
dense
small
>
mdi-dots-vertical
</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
dense
@click="removeContact(contact.id)"
>
<v-list-item-content>
<v-list-item-title
class="red--text"
>
<v-icon
left
small
color="red"
>
mdi-delete
</v-icon>
Remove
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>
</v-col>
</v-row>
</v-expansion-panel-header>
<v-expansion-panel-content>
<template>
<div>
<v-row
dense
>
<v-col
cols="12"
md="3"
>
<label>Given name:</label>
{{ contact.givenName }}
</v-col>
<v-col
cols="12"
md="3"
>
<label>Family name:</label>
{{ contact.familyName }}
</v-col>
</v-row>
<v-row
dense
>
<v-col
cols="12"
md="3"
>
<label>E-Mail:</label>
{{ contact.email | orDefault }}
</v-col>
<v-col
cols="12"
md="6"
>
<label>Website:</label>
{{ contact.website | orDefault }}
</v-col>
</v-row>
</div>
</template>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
<v-card-actions
v-if="!isAddContactPage && contacts.length > 3"
>
<v-spacer />
<v-btn
v-if="isLoggedIn"
color="primary"
small
nuxt
:to="'/platforms/' + platformId + '/contacts/new'"
>
Add contact
</v-btn>
</v-card-actions>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import { Contact } from '@/models/Contact'
import ProgressIndicator from '@/components/ProgressIndicator.vue'
@Component({
components: {
ProgressIndicator
}
})
export default class PlatformContactsPage extends Vue {
private contacts: Contact[] = []
private isLoading = false
private isSaving = false
mounted () {
this.isLoading = true
this.$api.platforms.findRelatedContacts(this.platformId).then((foundContacts) => {
this.contacts = foundContacts
this.isLoading = false
}).catch(() => {
this.$store.commit('snackbar/setError', 'Failed to fetch contacts')
this.isLoading = false
})
}
get isInProgress (): boolean {
return this.isLoading || this.isSaving
}
get platformId (): string {
return this.$route.params.platformId
}
get isLoggedIn (): boolean {
return this.$store.getters['oidc/isAuthenticated']
}
get isAddContactPage (): boolean {
return this.$route.path === '/platforms/' + this.platformId + '/contacts/new'
}
removeContact (contactId: string): void {
this.isSaving = true
this.$api.platforms.removeContact(this.platformId, contactId).then(() => {
const searchIndex = this.contacts.findIndex(c => c.id === contactId)
if (searchIndex > -1) {
this.contacts.splice(searchIndex, 1)
}
this.isSaving = false
}).catch((_error) => {
this.$store.commit('snackbar/setError', 'Removing contact failed')
this.isSaving = false
})
}
}
</script>
<template>
<div>
<ProgressIndicator
v-model="isInProgress"
:dark="isSaving"
/>
<v-row>
<v-col
cols="12"
md="5"
>
<v-autocomplete :items="allExceptSelected" :item-text="(x) => x" :item-value="(x) => x.id" label="New contact" @change="select" />
</v-col>
<v-col
cols="12"
md="2"
align-self="center"
>
<v-btn
small
color="primary"
:disabled="selectedContact == null"
@click="addContact"
>
Add
</v-btn>
<v-btn
small
text
nuxt
:to="'/platforms/' + platformId + '/contacts'"
>
Cancel
</v-btn>
</v-col>
</v-row>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from 'nuxt-property-decorator'
import { Contact } from '@/models/Contact'
import ProgressIndicator from '@/components/ProgressIndicator.vue'
@Component({
components: {
ProgressIndicator
}
})
export default class DeviceAddContactPage extends Vue {
private alreadyUsedContacts: Contact[] = []
private allContacts: Contact[] = []
private selectedContact: Contact | null = null
private isLoading: boolean = false
private isSaving: boolean = false
@Prop({
default: () => [] as Contact[],
required: true,
type: Array
})
readonly value!: Contact[]
created () {
this.alreadyUsedContacts = [...this.value] as Contact[]
}
mounted () {
this.isLoading = true
this.$api.contacts.findAll().then((foundContacts) => {
this.allContacts = foundContacts
this.isLoading = false
}).catch(() => {
this.$store.commit('snackbar/setError', 'Failed to fetch related contacts')
this.isLoading = false
})
}
get isInProgress (): boolean {
return this.isLoading || this.isSaving
}
addContact (): void {
if (this.selectedContact && this.selectedContact.id && this.isLoggedIn) {
this.isSaving = true
this.$api.platforms.addContact(this.platformId, this.selectedContact.id).then(() => {
this.isSaving = false
this.alreadyUsedContacts.push(this.selectedContact as Contact)
this.$emit('input', this.alreadyUsedContacts)
this.$router.push('/platforms/' + this.platformId + '/contacts')
}).catch(() => {
this.isSaving = false
this.$store.commit('snackbar/setError', 'Failed to save contacts')
})
}
}
select (newContactId: string): void {
const idx = this.allContacts.findIndex((c: Contact) => c.id === newContactId)
if (idx > -1) {
this.selectedContact = this.allContacts[idx]
} else {
this.selectedContact = null
}
}
get allExceptSelected (): Contact[] {
return this.allContacts.filter(c => !this.alreadyUsedContacts.find(rc => rc.id === c.id))
}
get platformId (): string {
return this.$route.params.platformId
}
get isLoggedIn (): boolean {
return this.$store.getters['oidc/isAuthenticated']
}
}
</script>
<template>
<div>
<ProgressIndicator
v-model="isLoading"
dark
/>
<v-card
flat
>
<v-card-actions>
<v-spacer />
<v-btn
v-if="isLoggedIn"
small
text
nuxt
to="/search/platforms"
>
cancel
</v-btn>
<v-btn
v-if="isLoggedIn"
color="green"
small
@click="onSaveButtonClicked"
>
create
</v-btn>
</v-card-actions>
<PlatformBasicDataForm
ref="basicForm"
v-model="platform"
/>
<v-card-actions>
<v-spacer />
<v-btn
v-if="isLoggedIn"
small
text
nuxt
to="/search/platforms"
>
cancel
</v-btn>
<v-btn
v-if="isLoggedIn"
color="green"
small
@click="onSaveButtonClicked"
>
create
</v-btn>
</v-card-actions>
</v-card>
</div>
</template>
<style lang="scss">
@import "@/assets/styles/_forms.scss";
</style>
<script lang="ts">
import { Component, mixins } from 'nuxt-property-decorator'
import { Rules } from '@/mixins/Rules'
import { Platform } from '@/models/Platform'
import ProgressIndicator from '@/components/ProgressIndicator.vue'
import PlatformBasicDataForm from '@/components/PlatformBasicDataForm.vue'
@Component({
components: {
PlatformBasicDataForm,
ProgressIndicator
}
})
// @ts-ignore
export default class PlatformNewPage extends mixins(Rules) {
private numberOfTabs: number = 1
private platform: Platform = new Platform()
private isLoading: boolean = false
mounted () {
this.initializeAppBar()
}
beforeDestroy () {
this.$store.dispatch('appbar/setDefaults')
}
onSaveButtonClicked (): void {
if (!(this.$refs.basicForm as Vue & { validateForm: () => boolean }).validateForm()) {
this.$store.commit('snackbar/setError', 'Please correct your input')
return
}
if (!this.isLoggedIn) {
this.$store.commit('snackbar/setError', 'You need to be logged in to save the platform')
return
}
this.isLoading = true
this.$api.platforms.save(this.platform).then((savedPlatform) => {
this.isLoading = false
this.$store.commit('snackbar/setSuccess', 'Platform created')
this.$router.push('/platforms/' + savedPlatform.id + '')
}).catch((_error) => {
this.isLoading = false
this.$store.commit('snackbar/setError', 'Save failed')
})
}
initializeAppBar () {
this.$store.dispatch('appbar/init', {
tabs: [
{
to: '/platforms/new',
name: 'Basic Data'
},
{
name: 'Contacts',
disabled: true
},
{
name: 'Attachments',
disabled: true
}
],
title: 'Add Platform'
})
}
get isLoggedIn () {
return this.$store.getters['oidc/isAuthenticated']
}
}
</script>
......@@ -464,7 +464,7 @@ permissions and limitations under the Licence.
fab
fixed
right
to="/platforms"
to="/platforms/new"
>
<v-icon>
mdi-plus
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment