Nextcloud-App/src/Ticket.vue

178 lines
4.9 KiB
Vue

<template>
<div class="single-ticket">
<div class="header-bar">
<button @click="back">
{{ t('upschooling', 'Zurück') }}
</button>
<button @click="save">
{{ t('upschooling', 'Speichern') }}
</button>
</div>
<h2>Ticket "ding"</h2>
<KeyValueTable :data-rows="{Id: ticket.ticketId, Name: ticket.title, Status: ticket.status, Geaendert: toLocaleDate(ticket.lastModified)}" />
<br>
<label for="description">{{ t('upschooling', 'Beschreibung') }}</label>
<textarea id="description" v-model.trim.lazy="description" rows="15" />
<br>
<button @click="save">
{{ t('upschooling', 'Speichern') }}
</button>
<hr>
<iframe id="element-web-frame"
src="about:blank"
title="Embedded Element Web"
width="100%"
height="400" />
</div>
</template>
<script>
import KeyValueTable from './components/KeyValueTable'
import axios from '@nextcloud/axios'
export default {
name: 'Ticket',
components: { KeyValueTable },
props: {
ticket: {
type: Object,
default() {
return {}
},
},
},
data() {
return {
description: this.ticket.description,
}
},
mounted() {
/** @type {HTMLIFrameElement} */
const elementWebFrame = document.getElementById('element-web-frame')
this.loadChat(elementWebFrame).catch((err) => {
if (err.message === 'Room not found') {
console.debug('No chat room assigned to ticket')
elementWebFrame.src = 'about:blank'
elementWebFrame.onload = function() {
const textElement = elementWebFrame.contentDocument.createElement('strong')
textElement.innerText = 'Textchat nicht verfügbar. Es ist noch kein(e) Helfer*in zugewiesen.'
elementWebFrame.contentDocument.body.appendChild(textElement)
elementWebFrame.onload = undefined
}
} else {
console.error('Could not load Element Web in iframe', err)
elementWebFrame.src = 'about:blank'
elementWebFrame.onload = function() {
const textElement = elementWebFrame.contentDocument.createElement('strong')
textElement.innerText = 'Element Web konnte nicht geladen werden.'
elementWebFrame.contentDocument.body.appendChild(textElement)
elementWebFrame.onload = undefined
}
}
})
},
methods: {
toLocaleDate(timestamp) {
const date = new Date(timestamp)
return date.toLocaleString()
},
save() {
this.$emit('save-ticket', this.ticket.ticketId, {}) // TODO: give it only the changed data
},
back() {
this.$emit('show-ticket-list')
},
async loadChat(elementWebFrame) {
const matrixInfoResponse = await axios.get(
`api/v1/tickets/${this.ticket.ticketId}/chat`,
{ headers: { Accept: 'application/json' }, validateStatus: status => status === 200 || status === 404 },
)
if (matrixInfoResponse.status === 404 && matrixInfoResponse.data.message === 'Room not found') {
throw Error(matrixInfoResponse.data.message)
}
if (matrixInfoResponse.status !== 200) {
throw Error(`Received unexpected status code ${matrixInfoResponse.status} for fetching matrix chat data`)
}
if (!matrixInfoResponse.data) {
throw Error('Did not receive any matrix chat data')
}
if (typeof matrixInfoResponse.data !== 'object') {
throw Error('Unexpected return value for fetching matrix chat data')
}
const loginPromise = new Promise(function(resolve, reject) {
const tryLogin = (elementWebFrame, matrixInfo, round) => {
if (elementWebFrame.contentWindow.mxLoginWithAccessToken === undefined) {
console.warn('Couldn\'t login in round ' + round)
setTimeout(() => {
tryLogin(elementWebFrame, matrixInfo, round + 1)
}, 1000)
} else {
elementWebFrame.contentWindow.mxLoginWithAccessToken(
matrixInfo.matrixServerUrl,
matrixInfo.matrixAccessToken,
).then(resolve).catch(reject)
}
}
elementWebFrame.onload = function() {
elementWebFrame.onload = undefined
tryLogin(elementWebFrame, matrixInfoResponse.data, 1)
}
})
// load Element Web
elementWebFrame.src = '/upschooling/element-web/'
loginPromise.then(async () => {
const matrixClient = elementWebFrame.contentWindow.mxMatrixClientPeg.get()
await matrixClient.joinRoom(matrixInfoResponse.data.matrixChatRoom)
elementWebFrame.contentWindow.mxDispatcher.dispatch({
action: 'view_room',
room_id: matrixInfoResponse.data.matrixChatRoom,
}, true)
// remove elements by CSS injection
const styleElement = elementWebFrame.contentDocument.createElement('style')
styleElement.innerText = `
.mx_LeftPanel_outerWrapper {
display: none !important;
}
.mx_NewRoomIntro {
display: none !important;
}
.mx_ToastContainer {
display: none !important;
}
`
elementWebFrame.contentDocument.head.appendChild(styleElement)
}).catch(console.error)
},
},
}
</script>
<style scoped>
textarea {
width: 100%;
margin: 0;
resize: vertical;
}
.placeholder {
height: 400px;
width: 100%;
background: #f0f0f0;
}
.header-bar {
display: flex;
width: 100%;
flex-direction: row-reverse;
}
</style>